feat(storage): 集成 MinIO 存储系统并支持用户签名功能
- 添加 MinIO 配置和依赖项,包括 minio、okhttp、okio 和 kotlin 库 - 创建通用文件服务接口和实现,支持文件上传到 MinIO 并记录元数据 - 添加用户签名服务接口和数据库表结构,支持签名文件管理 - 修改用户服务以支持签名文件上传,在新增和更新用户时可上传签名文件 - 实现文件预览服务测试用例的注释调整 - 创建 SysFile 和 SysUserSignature 数据库实体及对应常量类 - 实现 MinIO 存储组件,提供文件上传、下载和删除功能 - 在用户实体中添加签名相关字段用于展示签名信息
This commit is contained in:
@@ -37,6 +37,11 @@
|
||||
<version>1.2.83</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
<version>8.4.3</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -25,7 +25,9 @@ public enum UserResponseEnum {
|
||||
SUPER_ADMIN_REPEAT("A010013","超级管理员已存在,请勿重复添加" ),
|
||||
RSA_DECRYT_ERROR("A010014","RSA解密失败" ),
|
||||
PASSWORD_SAME("A010015", "新密码不能与旧密码相同"),
|
||||
OLD_PASSWORD_ERROR("A010016", "旧密码错误"), ;
|
||||
OLD_PASSWORD_ERROR("A010016", "旧密码错误"),
|
||||
SIGNATURE_FILE_NAME_EMPTY("A010017", "签名文件名不能为空"),
|
||||
SIGNATURE_FILE_TYPE_ERROR("A010018", "签名文件格式仅支持 png、jpg、jpeg、bmp、webp"), ;
|
||||
|
||||
private String code;
|
||||
private String message;
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
package com.njcn.gather.user.user.component;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import com.njcn.gather.user.user.config.StorageMinioProperties;
|
||||
import io.minio.BucketExistsArgs;
|
||||
import io.minio.GetObjectArgs;
|
||||
import io.minio.GetObjectResponse;
|
||||
import io.minio.MakeBucketArgs;
|
||||
import io.minio.MinioClient;
|
||||
import io.minio.PutObjectArgs;
|
||||
import io.minio.RemoveObjectArgs;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.MediaTypeFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* MinIO 通用文件存储服务。
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SysFileMinioStorageService {
|
||||
|
||||
private final StorageMinioProperties properties;
|
||||
|
||||
public StoredObjectInfo save(String bucketName, String bizDir, String ownerId, String fileId, MultipartFile file) {
|
||||
MultipartFile normalizedFile = requireFile(file);
|
||||
validateConfig();
|
||||
String originalFileName = normalizeFileName(normalizedFile.getOriginalFilename());
|
||||
String extension = resolveExtension(originalFileName);
|
||||
String objectName = buildObjectName(bizDir, ownerId, fileId, extension);
|
||||
String contentType = resolveContentType(normalizedFile, originalFileName);
|
||||
try (InputStream inputStream = normalizedFile.getInputStream()) {
|
||||
MinioClient client = buildClient();
|
||||
ensureBucket(client, bucketName);
|
||||
client.putObject(PutObjectArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(objectName)
|
||||
.stream(inputStream, normalizedFile.getSize(), -1)
|
||||
.contentType(contentType)
|
||||
.build());
|
||||
return new StoredObjectInfo(originalFileName, bucketName, objectName, contentType, normalizedFile.getSize());
|
||||
} catch (BusinessException exception) {
|
||||
throw exception;
|
||||
} catch (Exception exception) {
|
||||
log.error("upload file to minio failed, bucketName={}, objectName={}", bucketName, objectName, exception);
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "上传文件失败");
|
||||
}
|
||||
}
|
||||
|
||||
public StoredObject getObject(String bucketName, String objectName) {
|
||||
validateConfig();
|
||||
if (StrUtil.hasBlank(bucketName, objectName)) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "文件不存在");
|
||||
}
|
||||
try {
|
||||
GetObjectResponse response = buildClient().getObject(GetObjectArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(objectName)
|
||||
.build());
|
||||
return new StoredObject(response);
|
||||
} catch (BusinessException exception) {
|
||||
throw exception;
|
||||
} catch (Exception exception) {
|
||||
log.error("read file from minio failed, bucketName={}, objectName={}", bucketName, objectName, exception);
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "读取文件失败");
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteQuietly(String bucketName, String objectName) {
|
||||
if (StrUtil.hasBlank(bucketName, objectName)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
validateConfig();
|
||||
buildClient().removeObject(RemoveObjectArgs.builder()
|
||||
.bucket(bucketName)
|
||||
.object(objectName)
|
||||
.build());
|
||||
} catch (Exception exception) {
|
||||
log.warn("delete file from minio failed, bucketName={}, objectName={}", bucketName, objectName, exception);
|
||||
}
|
||||
}
|
||||
|
||||
private MultipartFile requireFile(MultipartFile file) {
|
||||
if (file == null || file.isEmpty()) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "上传文件不能为空");
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
private void validateConfig() {
|
||||
if (StrUtil.hasBlank(properties.getEndpoint(), properties.getAccessKey(), properties.getSecretKey())) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "MinIO配置不完整");
|
||||
}
|
||||
}
|
||||
|
||||
private MinioClient buildClient() {
|
||||
return MinioClient.builder()
|
||||
.endpoint(properties.getEndpoint())
|
||||
.credentials(properties.getAccessKey(), properties.getSecretKey())
|
||||
.build();
|
||||
}
|
||||
|
||||
private void ensureBucket(MinioClient client, String bucketName) throws Exception {
|
||||
boolean exists = client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
|
||||
if (!exists) {
|
||||
client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
|
||||
}
|
||||
}
|
||||
|
||||
private String normalizeFileName(String originalFileName) {
|
||||
String fileName = StrUtil.trimToEmpty(originalFileName);
|
||||
if (StrUtil.isBlank(fileName)) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "文件名不能为空");
|
||||
}
|
||||
int slashIndex = Math.max(fileName.lastIndexOf('/'), fileName.lastIndexOf('\\'));
|
||||
return slashIndex >= 0 ? fileName.substring(slashIndex + 1) : fileName;
|
||||
}
|
||||
|
||||
private String resolveExtension(String originalFileName) {
|
||||
int dotIndex = originalFileName.lastIndexOf('.');
|
||||
if (dotIndex < 0 || dotIndex == originalFileName.length() - 1) {
|
||||
return "bin";
|
||||
}
|
||||
return originalFileName.substring(dotIndex + 1).toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
private String buildObjectName(String bizDir, String ownerId, String fileId, String extension) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(trimPathSegment(bizDir));
|
||||
if (StrUtil.isNotBlank(ownerId)) {
|
||||
builder.append("/").append(trimPathSegment(ownerId));
|
||||
}
|
||||
builder.append("/").append(fileId);
|
||||
if (StrUtil.isNotBlank(extension)) {
|
||||
builder.append(".").append(extension);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private String trimPathSegment(String value) {
|
||||
String text = StrUtil.trimToEmpty(value);
|
||||
String normalized = text.replace("\\", "/");
|
||||
while (normalized.startsWith("/")) {
|
||||
normalized = normalized.substring(1);
|
||||
}
|
||||
while (normalized.endsWith("/")) {
|
||||
normalized = normalized.substring(0, normalized.length() - 1);
|
||||
}
|
||||
if (StrUtil.isBlank(normalized)) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "对象目录配置不合法");
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private String resolveContentType(MultipartFile file, String originalFileName) {
|
||||
if (StrUtil.isNotBlank(file.getContentType())) {
|
||||
return file.getContentType();
|
||||
}
|
||||
return MediaTypeFactory.getMediaType(originalFileName)
|
||||
.map(MediaType::toString)
|
||||
.orElse(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class StoredObjectInfo {
|
||||
private final String fileName;
|
||||
private final String bucketName;
|
||||
private final String objectName;
|
||||
private final String contentType;
|
||||
private final long fileSize;
|
||||
|
||||
public StoredObjectInfo(String fileName, String bucketName, String objectName, String contentType, long fileSize) {
|
||||
this.fileName = fileName;
|
||||
this.bucketName = bucketName;
|
||||
this.objectName = objectName;
|
||||
this.contentType = contentType;
|
||||
this.fileSize = fileSize;
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class StoredObject {
|
||||
private final GetObjectResponse inputStream;
|
||||
|
||||
public StoredObject(GetObjectResponse inputStream) {
|
||||
this.inputStream = inputStream;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.njcn.gather.user.user.config;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* MinIO 通用配置。
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "storage.minio")
|
||||
public class StorageMinioProperties {
|
||||
|
||||
/**
|
||||
* MinIO 服务地址。
|
||||
*/
|
||||
private String endpoint;
|
||||
|
||||
/**
|
||||
* MinIO 访问账号。
|
||||
*/
|
||||
private String accessKey;
|
||||
|
||||
/**
|
||||
* MinIO 访问密码。
|
||||
*/
|
||||
private String secretKey;
|
||||
|
||||
/**
|
||||
* 业务桶配置。
|
||||
*/
|
||||
private Map<String, String> buckets = new LinkedHashMap<String, String>();
|
||||
|
||||
public String requireBucket(String bucketKey) {
|
||||
String bucketName = buckets.get(bucketKey);
|
||||
if (StrUtil.isBlank(bucketName)) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "MinIO桶配置缺失:" + bucketKey);
|
||||
}
|
||||
return bucketName;
|
||||
}
|
||||
}
|
||||
@@ -7,24 +7,35 @@ import com.njcn.common.pojo.constant.OperateType;
|
||||
import com.njcn.common.pojo.enums.common.DataStateEnum;
|
||||
import com.njcn.common.pojo.enums.common.LogEnum;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import com.njcn.common.pojo.response.HttpResult;
|
||||
import com.njcn.common.utils.LogUtil;
|
||||
import com.njcn.gather.user.user.pojo.param.SysUserParam;
|
||||
import com.njcn.gather.user.user.pojo.po.SysFile;
|
||||
import com.njcn.gather.user.user.pojo.po.SysRole;
|
||||
import com.njcn.gather.user.user.pojo.po.SysUser;
|
||||
import com.njcn.gather.user.user.pojo.po.SysUserSignature;
|
||||
import com.njcn.gather.user.user.service.ISysFileService;
|
||||
import com.njcn.gather.user.user.service.ISysUserRoleService;
|
||||
import com.njcn.gather.user.user.service.ISysUserSignatureService;
|
||||
import com.njcn.gather.user.user.service.ISysUserService;
|
||||
import com.njcn.gather.user.user.component.SysFileMinioStorageService;
|
||||
import com.njcn.web.controller.BaseController;
|
||||
import com.njcn.web.utils.HttpResultUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -42,6 +53,9 @@ public class SysUserController extends BaseController {
|
||||
|
||||
private final ISysUserService sysUserService;
|
||||
private final ISysUserRoleService sysUserRoleService;
|
||||
private final ISysUserSignatureService sysUserSignatureService;
|
||||
private final ISysFileService sysFileService;
|
||||
private final SysFileMinioStorageService sysFileMinioStorageService;
|
||||
|
||||
@OperateInfo(info = LogEnum.SYSTEM_COMMON)
|
||||
@PostMapping("/list")
|
||||
@@ -55,13 +69,14 @@ public class SysUserController extends BaseController {
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.SYSTEM_COMMON, operateType = OperateType.ADD)
|
||||
@PostMapping("/add")
|
||||
@PostMapping(value = "/add", consumes = {"multipart/form-data"})
|
||||
@ApiOperation("新增用户")
|
||||
@ApiImplicitParam(name = "addUserParam", value = "新增用户", required = true)
|
||||
public HttpResult<Boolean> add(@RequestBody @Validated SysUserParam.SysUserAddParam addUserParam) {
|
||||
public HttpResult<Boolean> add(@RequestPart("request") @Validated SysUserParam.SysUserAddParam addUserParam,
|
||||
@RequestPart(value = "signatureFile", required = false) MultipartFile signatureFile) {
|
||||
String methodDescribe = getMethodDescribe("add");
|
||||
LogUtil.njcnDebug(log, "{},用户数据为:{}", methodDescribe, addUserParam);
|
||||
boolean result = sysUserService.addUser(addUserParam);
|
||||
boolean result = sysUserService.addUser(addUserParam, signatureFile);
|
||||
if (result) {
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe);
|
||||
} else {
|
||||
@@ -70,13 +85,14 @@ public class SysUserController extends BaseController {
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.SYSTEM_COMMON, operateType = OperateType.UPDATE)
|
||||
@PostMapping("/update")
|
||||
@PostMapping(value = "/update", consumes = {"multipart/form-data"})
|
||||
@ApiOperation("修改用户")
|
||||
@ApiImplicitParam(name = "updateUserParam", value = "修改用户", required = true)
|
||||
public HttpResult<Boolean> update(@RequestBody @Validated SysUserParam.SysUserUpdateParam updateUserParam) {
|
||||
public HttpResult<Boolean> update(@RequestPart("request") @Validated SysUserParam.SysUserUpdateParam updateUserParam,
|
||||
@RequestPart(value = "signatureFile", required = false) MultipartFile signatureFile) {
|
||||
String methodDescribe = getMethodDescribe("update");
|
||||
LogUtil.njcnDebug(log, "{},用户数据为:{}", methodDescribe, updateUserParam);
|
||||
boolean result = sysUserService.updateUser(updateUserParam);
|
||||
boolean result = sysUserService.updateUser(updateUserParam, signatureFile);
|
||||
if (result) {
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, true, methodDescribe);
|
||||
} else {
|
||||
@@ -128,7 +144,43 @@ public class SysUserController extends BaseController {
|
||||
user.setRoleCodes(sysRoles.stream().map(SysRole::getCode).collect(Collectors.toList()));
|
||||
user.setRoleNames(sysRoles.stream().map(SysRole::getName).collect(Collectors.toList()));
|
||||
});
|
||||
sysUserSignatureService.fillSignatureInfo(result);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.SYSTEM_COMMON)
|
||||
@GetMapping("/{id}/signature")
|
||||
@ApiOperation("预览用户签名")
|
||||
@ApiImplicitParam(name = "id", value = "用户id", required = true)
|
||||
public ResponseEntity<InputStreamResource> signature(@PathVariable("id") String id) {
|
||||
SysUserSignature signature = sysUserSignatureService.getActiveByUserId(id);
|
||||
if (signature == null) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "用户签名不存在");
|
||||
}
|
||||
SysFile sysFile = sysFileService.getActiveById(signature.getFileId());
|
||||
if (sysFile == null) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "用户签名文件不存在");
|
||||
}
|
||||
SysFileMinioStorageService.StoredObject storedObject =
|
||||
sysFileMinioStorageService.getObject(sysFile.getBucketName(), sysFile.getObjectName());
|
||||
String encodedFileName;
|
||||
try {
|
||||
encodedFileName = URLEncoder.encode(sysFile.getFileName(), "UTF-8")
|
||||
.replace("+", "%20");
|
||||
} catch (Exception exception) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "读取用户签名失败");
|
||||
}
|
||||
MediaType mediaType;
|
||||
try {
|
||||
mediaType = sysFile.getContentType() == null ? MediaType.APPLICATION_OCTET_STREAM
|
||||
: MediaType.parseMediaType(sysFile.getContentType());
|
||||
} catch (Exception exception) {
|
||||
mediaType = MediaType.APPLICATION_OCTET_STREAM;
|
||||
}
|
||||
return ResponseEntity.ok()
|
||||
.contentType(mediaType)
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename*=UTF-8''" + encodedFileName)
|
||||
.body(new InputStreamResource(storedObject.getInputStream()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.njcn.gather.user.user.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.njcn.gather.user.user.pojo.po.SysFile;
|
||||
|
||||
/**
|
||||
* 通用文件 Mapper。
|
||||
*/
|
||||
public interface SysFileMapper extends BaseMapper<SysFile> {
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.njcn.gather.user.user.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.njcn.gather.user.user.pojo.po.SysUserSignature;
|
||||
|
||||
/**
|
||||
* 用户签名 Mapper。
|
||||
*/
|
||||
public interface SysUserSignatureMapper extends BaseMapper<SysUserSignature> {
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.njcn.gather.user.user.pojo.constant;
|
||||
|
||||
/**
|
||||
* 通用文件常量。
|
||||
*/
|
||||
public final class SysFileConst {
|
||||
|
||||
private SysFileConst() {
|
||||
}
|
||||
|
||||
public static final Integer STATUS_DELETED = 0;
|
||||
public static final Integer STATUS_NORMAL = 1;
|
||||
|
||||
public static final String STORAGE_TYPE_MINIO = "MINIO";
|
||||
|
||||
public static final String BIZ_TYPE_USER_SIGNATURE = "USER_SIGNATURE";
|
||||
public static final String BIZ_DIR_USER_SIGNATURE = "user-signature";
|
||||
public static final String BUCKET_KEY_USER_SIGNATURE = "user-signature";
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.njcn.gather.user.user.pojo.constant;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 通用文件扩展名常量。
|
||||
*/
|
||||
public final class SysFileExtensionConst {
|
||||
|
||||
private SysFileExtensionConst() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片文件扩展名,适用于签名、图片附件等场景。
|
||||
*/
|
||||
public static final Set<String> IMAGE_EXTENSIONS = unmodifiableSet(
|
||||
"png", "jpg", "jpeg", "bmp", "webp");
|
||||
|
||||
/**
|
||||
* 常见文档文件扩展名,适用于文档、台账、说明文件等场景。
|
||||
*/
|
||||
public static final Set<String> DOCUMENT_EXTENSIONS = unmodifiableSet(
|
||||
"doc", "docx", "xls", "xlsx", "txt", "pdf");
|
||||
|
||||
/**
|
||||
* 通用上传扩展名,供后续文件业务按需复用。
|
||||
*/
|
||||
public static final Set<String> COMMON_UPLOAD_EXTENSIONS = merge(IMAGE_EXTENSIONS, DOCUMENT_EXTENSIONS);
|
||||
|
||||
private static Set<String> merge(Set<String> left, Set<String> right) {
|
||||
LinkedHashSet<String> merged = new LinkedHashSet<String>();
|
||||
merged.addAll(left);
|
||||
merged.addAll(right);
|
||||
return Collections.unmodifiableSet(merged);
|
||||
}
|
||||
|
||||
private static Set<String> unmodifiableSet(String... values) {
|
||||
return Collections.unmodifiableSet(new LinkedHashSet<String>(Arrays.asList(values)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.njcn.gather.user.user.pojo.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.njcn.db.mybatisplus.bo.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 通用文件记录。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("sys_file")
|
||||
public class SysFile extends BaseEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -5516228278748156912L;
|
||||
|
||||
@TableId("id")
|
||||
private String id;
|
||||
|
||||
@TableField("biz_type")
|
||||
private String bizType;
|
||||
|
||||
@TableField("file_name")
|
||||
private String fileName;
|
||||
|
||||
@TableField("bucket_name")
|
||||
private String bucketName;
|
||||
|
||||
@TableField("object_name")
|
||||
private String objectName;
|
||||
|
||||
@TableField("content_type")
|
||||
private String contentType;
|
||||
|
||||
@TableField("file_size")
|
||||
private Long fileSize;
|
||||
|
||||
@TableField("storage_type")
|
||||
private String storageType;
|
||||
|
||||
@TableField("status")
|
||||
private Integer status;
|
||||
}
|
||||
@@ -94,5 +94,11 @@ public class SysUser extends BaseEntity implements Serializable {
|
||||
|
||||
@TableField(exist = false)
|
||||
private List<String> roleNames;
|
||||
|
||||
@TableField(exist = false)
|
||||
private String signatureFileId;
|
||||
|
||||
@TableField(exist = false)
|
||||
private String signatureFileName;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.njcn.gather.user.user.pojo.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.njcn.db.mybatisplus.bo.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 用户签名记录。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("sys_user_signature")
|
||||
public class SysUserSignature extends BaseEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 5765362638635953846L;
|
||||
|
||||
@TableId("id")
|
||||
private String id;
|
||||
|
||||
@TableField("user_id")
|
||||
private String userId;
|
||||
|
||||
@TableField("user_name")
|
||||
private String userName;
|
||||
|
||||
@TableField("file_id")
|
||||
private String fileId;
|
||||
|
||||
@TableField("status")
|
||||
private Integer status;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.njcn.gather.user.user.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.njcn.gather.user.user.pojo.po.SysFile;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通用文件服务。
|
||||
*/
|
||||
public interface ISysFileService extends IService<SysFile> {
|
||||
|
||||
/**
|
||||
* 上传并保存 MinIO 文件记录。
|
||||
*
|
||||
* @param bizType 业务类型
|
||||
* @param bucketKey 桶配置键
|
||||
* @param bizDir MinIO 目录
|
||||
* @param ownerId 业务归属ID
|
||||
* @param file 上传文件
|
||||
* @return 文件记录
|
||||
*/
|
||||
SysFile saveMinioFile(String bizType, String bucketKey, String bizDir, String ownerId, MultipartFile file);
|
||||
|
||||
/**
|
||||
* 根据 ID 查询有效文件。
|
||||
*
|
||||
* @param fileId 文件ID
|
||||
* @return 文件记录
|
||||
*/
|
||||
SysFile getActiveById(String fileId);
|
||||
|
||||
/**
|
||||
* 按文件 ID 列表查询有效文件。
|
||||
*
|
||||
* @param fileIds 文件ID列表
|
||||
* @return 文件记录
|
||||
*/
|
||||
List<SysFile> listActiveByIds(List<String> fileIds);
|
||||
|
||||
/**
|
||||
* 逻辑删除文件记录。
|
||||
*
|
||||
* @param file 文件记录
|
||||
*/
|
||||
void markDeleted(SysFile file);
|
||||
|
||||
/**
|
||||
* 删除 MinIO 对象。
|
||||
*
|
||||
* @param file 文件记录
|
||||
*/
|
||||
void deleteObjectQuietly(SysFile file);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.njcn.gather.user.user.pojo.param.SysUserParam;
|
||||
import com.njcn.gather.user.user.pojo.po.SysUser;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -64,7 +65,7 @@ public interface ISysUserService extends IService<SysUser> {
|
||||
* @param addUserParam 新增用户参数
|
||||
* @return 结果,true表示新增成功,false表示新增失败
|
||||
*/
|
||||
boolean addUser(SysUserParam.SysUserAddParam addUserParam);
|
||||
boolean addUser(SysUserParam.SysUserAddParam addUserParam, MultipartFile signatureFile);
|
||||
|
||||
/**
|
||||
* 更新用户
|
||||
@@ -72,7 +73,7 @@ public interface ISysUserService extends IService<SysUser> {
|
||||
* @param updateUserParam 更新用户参数
|
||||
* @return 结果,true表示更新成功,false表示更新失败
|
||||
*/
|
||||
boolean updateUser(SysUserParam.SysUserUpdateParam updateUserParam);
|
||||
boolean updateUser(SysUserParam.SysUserUpdateParam updateUserParam, MultipartFile signatureFile);
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.njcn.gather.user.user.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.njcn.gather.user.user.pojo.po.SysUser;
|
||||
import com.njcn.gather.user.user.pojo.po.SysUserSignature;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户签名服务。
|
||||
*/
|
||||
public interface ISysUserSignatureService extends IService<SysUserSignature> {
|
||||
|
||||
/**
|
||||
* 回填用户签名展示信息。
|
||||
*
|
||||
* @param users 用户列表
|
||||
*/
|
||||
void fillSignatureInfo(List<SysUser> users);
|
||||
|
||||
/**
|
||||
* 查询用户当前签名。
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 签名记录
|
||||
*/
|
||||
SysUserSignature getActiveByUserId(String userId);
|
||||
|
||||
/**
|
||||
* 保存或更新签名元数据。
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param userName 用户名
|
||||
* @param fileId 通用文件ID
|
||||
* @return 旧签名记录,若不存在则返回 null
|
||||
*/
|
||||
SysUserSignature saveOrUpdateSignature(String userId, String userName, String fileId);
|
||||
|
||||
/**
|
||||
* 同步签名记录中的用户名。
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param userName 用户名
|
||||
*/
|
||||
void syncUserName(String userId, String userName);
|
||||
|
||||
/**
|
||||
* 查询用户签名列表。
|
||||
*
|
||||
* @param userIds 用户ID列表
|
||||
* @return 签名记录
|
||||
*/
|
||||
List<SysUserSignature> listActiveByUserIds(List<String> userIds);
|
||||
|
||||
/**
|
||||
* 逻辑删除用户签名记录。
|
||||
*
|
||||
* @param signatures 签名记录
|
||||
*/
|
||||
void markDeleted(List<SysUserSignature> signatures);
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.njcn.gather.user.user.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import com.njcn.gather.user.user.component.SysFileMinioStorageService;
|
||||
import com.njcn.gather.user.user.config.StorageMinioProperties;
|
||||
import com.njcn.gather.user.user.mapper.SysFileMapper;
|
||||
import com.njcn.gather.user.user.pojo.constant.SysFileConst;
|
||||
import com.njcn.gather.user.user.pojo.po.SysFile;
|
||||
import com.njcn.gather.user.user.service.ISysFileService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 通用文件服务实现。
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SysFileServiceImpl extends ServiceImpl<SysFileMapper, SysFile> implements ISysFileService {
|
||||
|
||||
private final StorageMinioProperties storageMinioProperties;
|
||||
private final SysFileMinioStorageService sysFileMinioStorageService;
|
||||
|
||||
@Override
|
||||
public SysFile saveMinioFile(String bizType, String bucketKey, String bizDir, String ownerId, MultipartFile file) {
|
||||
String fileId = UUID.randomUUID().toString().replace("-", "");
|
||||
String bucketName = storageMinioProperties.requireBucket(bucketKey);
|
||||
SysFileMinioStorageService.StoredObjectInfo storedObjectInfo =
|
||||
sysFileMinioStorageService.save(bucketName, bizDir, ownerId, fileId, file);
|
||||
SysFile sysFile = new SysFile();
|
||||
sysFile.setId(fileId);
|
||||
sysFile.setBizType(bizType);
|
||||
sysFile.setFileName(storedObjectInfo.getFileName());
|
||||
sysFile.setBucketName(storedObjectInfo.getBucketName());
|
||||
sysFile.setObjectName(storedObjectInfo.getObjectName());
|
||||
sysFile.setContentType(storedObjectInfo.getContentType());
|
||||
sysFile.setFileSize(storedObjectInfo.getFileSize());
|
||||
sysFile.setStorageType(SysFileConst.STORAGE_TYPE_MINIO);
|
||||
sysFile.setStatus(SysFileConst.STATUS_NORMAL);
|
||||
try {
|
||||
boolean saved = this.save(sysFile);
|
||||
if (!saved) {
|
||||
sysFileMinioStorageService.deleteQuietly(sysFile.getBucketName(), sysFile.getObjectName());
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "保存文件记录失败");
|
||||
}
|
||||
return sysFile;
|
||||
} catch (RuntimeException exception) {
|
||||
sysFileMinioStorageService.deleteQuietly(sysFile.getBucketName(), sysFile.getObjectName());
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysFile getActiveById(String fileId) {
|
||||
if (fileId == null || fileId.trim().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return this.lambdaQuery()
|
||||
.eq(SysFile::getId, fileId)
|
||||
.eq(SysFile::getStatus, SysFileConst.STATUS_NORMAL)
|
||||
.one();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysFile> listActiveByIds(List<String> fileIds) {
|
||||
if (CollUtil.isEmpty(fileIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return this.lambdaQuery()
|
||||
.in(SysFile::getId, fileIds)
|
||||
.eq(SysFile::getStatus, SysFileConst.STATUS_NORMAL)
|
||||
.list();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markDeleted(SysFile file) {
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
file.setStatus(SysFileConst.STATUS_DELETED);
|
||||
this.updateById(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteObjectQuietly(SysFile file) {
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
sysFileMinioStorageService.deleteQuietly(file.getBucketName(), file.getObjectName());
|
||||
}
|
||||
}
|
||||
@@ -13,35 +13,43 @@ import com.njcn.db.mybatisplus.constant.DbConstant;
|
||||
import com.njcn.gather.user.pojo.constant.RoleConst;
|
||||
import com.njcn.gather.user.pojo.constant.UserConst;
|
||||
import com.njcn.gather.user.pojo.enums.UserResponseEnum;
|
||||
import com.njcn.gather.user.user.pojo.constant.SysFileExtensionConst;
|
||||
import com.njcn.gather.user.user.mapper.SysUserMapper;
|
||||
import com.njcn.gather.user.user.pojo.constant.SysFileConst;
|
||||
import com.njcn.gather.user.user.pojo.param.SysUserParam;
|
||||
import com.njcn.gather.user.user.pojo.po.SysFile;
|
||||
import com.njcn.gather.user.user.pojo.po.SysRole;
|
||||
import com.njcn.gather.user.user.pojo.po.SysUser;
|
||||
import com.njcn.gather.user.user.pojo.po.SysUserSignature;
|
||||
import com.njcn.gather.user.user.service.ISysFileService;
|
||||
import com.njcn.gather.user.user.service.ISysUserRoleService;
|
||||
import com.njcn.gather.user.user.service.ISysUserSignatureService;
|
||||
import com.njcn.gather.user.user.service.ISysUserService;
|
||||
import com.njcn.web.factory.PageFactory;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author caozehui
|
||||
* @date 2024-11-08
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {
|
||||
|
||||
private final ISysUserRoleService sysUserRoleService;
|
||||
private final ISysFileService sysFileService;
|
||||
private final ISysUserSignatureService sysUserSignatureService;
|
||||
|
||||
@Override
|
||||
public Page<SysUser> listUser(SysUserParam.SysUserQueryParam queryParam) {
|
||||
@@ -65,6 +73,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
sysUser.setRoleIds(sysRoles.stream().map(SysRole::getId).collect(Collectors.toList()));
|
||||
sysUser.setRoleNames(sysRoles.stream().map(SysRole::getName).collect(Collectors.toList()));
|
||||
});
|
||||
sysUserSignatureService.fillSignatureInfo(page.getRecords());
|
||||
return page;
|
||||
}
|
||||
|
||||
@@ -105,7 +114,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean addUser(SysUserParam.SysUserAddParam addUserParam) {
|
||||
public boolean addUser(SysUserParam.SysUserAddParam addUserParam, MultipartFile signatureFile) {
|
||||
addUserParam.setName(addUserParam.getName().trim());
|
||||
addUserParam.setLoginName(addUserParam.getLoginName().trim());
|
||||
if (UserConst.SUPER_ADMIN.equals(addUserParam.getLoginName())) {
|
||||
@@ -117,26 +126,79 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
checkRepeat(addUserParam, false, null);
|
||||
SysUser sysUser = new SysUser();
|
||||
BeanUtils.copyProperties(addUserParam, sysUser);
|
||||
sysUser.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||
String secretkey = Sm4Utils.globalSecretKey;
|
||||
Sm4Utils sm4 = new Sm4Utils(secretkey);
|
||||
sysUser.setPassword(sm4.encryptData_ECB(sysUser.getPassword()));
|
||||
sysUser.setLoginTime(LocalDateTimeUtil.now());
|
||||
sysUser.setLoginErrorTimes(0);
|
||||
sysUser.setState(UserConst.STATE_ENABLE);
|
||||
boolean result = this.save(sysUser);
|
||||
sysUserRoleService.addUserRole(sysUser.getId(), addUserParam.getRoleIds());
|
||||
return result;
|
||||
MultipartFile normalizedSignature = normalizeSignatureFile(signatureFile);
|
||||
SysFile sysFile = null;
|
||||
if (normalizedSignature != null) {
|
||||
sysFile = sysFileService.saveMinioFile(SysFileConst.BIZ_TYPE_USER_SIGNATURE,
|
||||
SysFileConst.BUCKET_KEY_USER_SIGNATURE, SysFileConst.BIZ_DIR_USER_SIGNATURE,
|
||||
sysUser.getId(), normalizedSignature);
|
||||
}
|
||||
try {
|
||||
boolean result = this.save(sysUser);
|
||||
if (result) {
|
||||
sysUserRoleService.addUserRole(sysUser.getId(), addUserParam.getRoleIds());
|
||||
if (sysFile != null) {
|
||||
sysUserSignatureService.saveOrUpdateSignature(sysUser.getId(), sysUser.getName(), sysFile.getId());
|
||||
}
|
||||
}
|
||||
if (!result && sysFile != null) {
|
||||
cleanupNewFile(sysFile);
|
||||
}
|
||||
return result;
|
||||
} catch (RuntimeException exception) {
|
||||
if (sysFile != null) {
|
||||
cleanupNewFile(sysFile);
|
||||
}
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean updateUser(SysUserParam.SysUserUpdateParam updateUserParam) {
|
||||
public boolean updateUser(SysUserParam.SysUserUpdateParam updateUserParam, MultipartFile signatureFile) {
|
||||
updateUserParam.setName(updateUserParam.getName().trim());
|
||||
checkRepeat(updateUserParam, true, updateUserParam.getId());
|
||||
SysUser sysUser = new SysUser();
|
||||
BeanUtils.copyProperties(updateUserParam, sysUser);
|
||||
sysUserRoleService.updateUserRole(sysUser.getId(), updateUserParam.getRoleIds());
|
||||
return this.updateById(sysUser);
|
||||
MultipartFile normalizedSignature = normalizeSignatureFile(signatureFile);
|
||||
SysFile newSysFile = null;
|
||||
if (normalizedSignature != null) {
|
||||
newSysFile = sysFileService.saveMinioFile(SysFileConst.BIZ_TYPE_USER_SIGNATURE,
|
||||
SysFileConst.BUCKET_KEY_USER_SIGNATURE, SysFileConst.BIZ_DIR_USER_SIGNATURE,
|
||||
sysUser.getId(), normalizedSignature);
|
||||
}
|
||||
try {
|
||||
boolean updated = this.updateById(sysUser);
|
||||
if (!updated) {
|
||||
if (newSysFile != null) {
|
||||
cleanupNewFile(newSysFile);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
sysUserRoleService.updateUserRole(sysUser.getId(), updateUserParam.getRoleIds());
|
||||
if (newSysFile != null) {
|
||||
SysUserSignature oldSignature = sysUserSignatureService.saveOrUpdateSignature(
|
||||
sysUser.getId(), sysUser.getName(), newSysFile.getId());
|
||||
if (oldSignature != null) {
|
||||
cleanupOldFile(oldSignature.getFileId());
|
||||
}
|
||||
} else {
|
||||
sysUserSignatureService.syncUserName(sysUser.getId(), sysUser.getName());
|
||||
}
|
||||
return true;
|
||||
} catch (RuntimeException exception) {
|
||||
if (newSysFile != null) {
|
||||
cleanupNewFile(newSysFile);
|
||||
}
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -170,12 +232,18 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
}
|
||||
}
|
||||
}
|
||||
List<SysUserSignature> signatures = sysUserSignatureService.listActiveByUserIds(ids);
|
||||
// 删除用户角色关联数据
|
||||
sysUserRoleService.deleteUserRoleByUserIds(ids);
|
||||
return this.lambdaUpdate()
|
||||
boolean result = this.lambdaUpdate()
|
||||
.set(SysUser::getState, UserConst.STATE_DELETE)
|
||||
.in(SysUser::getId, ids)
|
||||
.update();
|
||||
if (result) {
|
||||
sysUserSignatureService.markDeleted(signatures);
|
||||
signatures.forEach(signature -> cleanupOldFile(signature.getFileId()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -210,4 +278,37 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
throw new BusinessException(UserResponseEnum.REGISTER_EMAIL_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
private MultipartFile normalizeSignatureFile(MultipartFile signatureFile) {
|
||||
if (signatureFile == null || signatureFile.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
String originalFileName = signatureFile.getOriginalFilename();
|
||||
if (originalFileName == null || originalFileName.trim().isEmpty()) {
|
||||
throw new BusinessException(UserResponseEnum.SIGNATURE_FILE_NAME_EMPTY);
|
||||
}
|
||||
int dotIndex = originalFileName.lastIndexOf('.');
|
||||
if (dotIndex < 0 || dotIndex == originalFileName.length() - 1) {
|
||||
throw new BusinessException(UserResponseEnum.SIGNATURE_FILE_TYPE_ERROR);
|
||||
}
|
||||
String extension = originalFileName.substring(dotIndex + 1).toLowerCase(Locale.ENGLISH);
|
||||
if (!SysFileExtensionConst.IMAGE_EXTENSIONS.contains(extension)) {
|
||||
throw new BusinessException(UserResponseEnum.SIGNATURE_FILE_TYPE_ERROR);
|
||||
}
|
||||
return signatureFile;
|
||||
}
|
||||
|
||||
private void cleanupNewFile(SysFile sysFile) {
|
||||
sysFileService.markDeleted(sysFile);
|
||||
sysFileService.deleteObjectQuietly(sysFile);
|
||||
}
|
||||
|
||||
private void cleanupOldFile(String fileId) {
|
||||
SysFile oldFile = sysFileService.getActiveById(fileId);
|
||||
if (oldFile == null) {
|
||||
return;
|
||||
}
|
||||
sysFileService.markDeleted(oldFile);
|
||||
sysFileService.deleteObjectQuietly(oldFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.njcn.gather.user.user.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.njcn.gather.user.user.mapper.SysUserSignatureMapper;
|
||||
import com.njcn.gather.user.user.pojo.constant.SysFileConst;
|
||||
import com.njcn.gather.user.user.pojo.po.SysFile;
|
||||
import com.njcn.gather.user.user.pojo.po.SysUser;
|
||||
import com.njcn.gather.user.user.pojo.po.SysUserSignature;
|
||||
import com.njcn.gather.user.user.service.ISysFileService;
|
||||
import com.njcn.gather.user.user.service.ISysUserSignatureService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 用户签名服务实现。
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SysUserSignatureServiceImpl extends ServiceImpl<SysUserSignatureMapper, SysUserSignature>
|
||||
implements ISysUserSignatureService {
|
||||
|
||||
private final ISysFileService sysFileService;
|
||||
|
||||
@Override
|
||||
public void fillSignatureInfo(List<SysUser> users) {
|
||||
if (CollUtil.isEmpty(users)) {
|
||||
return;
|
||||
}
|
||||
Map<String, SysUserSignature> signatureMap = new LinkedHashMap<String, SysUserSignature>();
|
||||
List<String> userIds = users.stream().map(SysUser::getId).collect(Collectors.toList());
|
||||
for (SysUserSignature signature : listActiveByUserIds(userIds)) {
|
||||
signatureMap.put(signature.getUserId(), signature);
|
||||
}
|
||||
Map<String, SysFile> sysFileMap = new LinkedHashMap<String, SysFile>();
|
||||
List<String> fileIds = signatureMap.values().stream().map(SysUserSignature::getFileId).collect(Collectors.toList());
|
||||
for (SysFile sysFile : sysFileService.listActiveByIds(fileIds)) {
|
||||
sysFileMap.put(sysFile.getId(), sysFile);
|
||||
}
|
||||
for (SysUser user : users) {
|
||||
SysUserSignature signature = signatureMap.get(user.getId());
|
||||
if (signature == null) {
|
||||
user.setSignatureFileId(null);
|
||||
user.setSignatureFileName(null);
|
||||
continue;
|
||||
}
|
||||
user.setSignatureFileId(signature.getFileId());
|
||||
SysFile sysFile = sysFileMap.get(signature.getFileId());
|
||||
user.setSignatureFileName(sysFile == null ? null : sysFile.getFileName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysUserSignature getActiveByUserId(String userId) {
|
||||
if (StrUtil.isBlank(userId)) {
|
||||
return null;
|
||||
}
|
||||
return this.lambdaQuery()
|
||||
.eq(SysUserSignature::getUserId, userId)
|
||||
.eq(SysUserSignature::getStatus, SysFileConst.STATUS_NORMAL)
|
||||
.one();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysUserSignature saveOrUpdateSignature(String userId, String userName, String fileId) {
|
||||
SysUserSignature existing = getActiveByUserId(userId);
|
||||
if (existing == null) {
|
||||
SysUserSignature signature = new SysUserSignature();
|
||||
signature.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||
signature.setUserId(userId);
|
||||
signature.setUserName(userName);
|
||||
signature.setFileId(fileId);
|
||||
signature.setStatus(SysFileConst.STATUS_NORMAL);
|
||||
this.save(signature);
|
||||
return null;
|
||||
}
|
||||
SysUserSignature oldSignature = copySignature(existing);
|
||||
existing.setUserName(userName);
|
||||
existing.setFileId(fileId);
|
||||
existing.setStatus(SysFileConst.STATUS_NORMAL);
|
||||
this.updateById(existing);
|
||||
return oldSignature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncUserName(String userId, String userName) {
|
||||
SysUserSignature signature = getActiveByUserId(userId);
|
||||
if (signature == null || StrUtil.equals(signature.getUserName(), userName)) {
|
||||
return;
|
||||
}
|
||||
signature.setUserName(userName);
|
||||
this.updateById(signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysUserSignature> listActiveByUserIds(List<String> userIds) {
|
||||
if (CollUtil.isEmpty(userIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return this.lambdaQuery()
|
||||
.in(SysUserSignature::getUserId, userIds)
|
||||
.eq(SysUserSignature::getStatus, SysFileConst.STATUS_NORMAL)
|
||||
.list();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markDeleted(List<SysUserSignature> signatures) {
|
||||
if (CollUtil.isEmpty(signatures)) {
|
||||
return;
|
||||
}
|
||||
for (SysUserSignature signature : signatures) {
|
||||
signature.setStatus(SysFileConst.STATUS_DELETED);
|
||||
this.updateById(signature);
|
||||
}
|
||||
}
|
||||
|
||||
private SysUserSignature copySignature(SysUserSignature source) {
|
||||
SysUserSignature copy = new SysUserSignature();
|
||||
copy.setId(source.getId());
|
||||
copy.setUserId(source.getUserId());
|
||||
copy.setUserName(source.getUserName());
|
||||
copy.setFileId(source.getFileId());
|
||||
copy.setStatus(source.getStatus());
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user