feat(personal-center): 个人头像更新

This commit is contained in:
caozehui
2026-05-19 10:56:13 +08:00
parent 1ef86fc1cb
commit b6d31ab156
4 changed files with 125 additions and 21 deletions

View File

@@ -60,6 +60,10 @@ public interface ErrorCodeConstants {
ErrorCode USER_MANAGEMENT_RELATION_NOT_FOUND = new ErrorCode(1_002_003_100, "用户管理链路不存在");
ErrorCode USER_MANAGEMENT_RELATION_MANAGER_EXISTS = new ErrorCode(1_002_003_101, "该用户已有直属上级,不能重复添加");
ErrorCode USER_MANAGEMENT_RELATION_EXISTS = new ErrorCode(1_002_003_102, "该用户在管理链路中还在使用,不可删除!");
ErrorCode USER_AVATAR_SUFFIX_ERROR = new ErrorCode(1_002_003_103, "头像文件格式错误");
ErrorCode USER_AVATAR_SIZE_ERROR = new ErrorCode(1_002_003_104, "头像文件大小不能超过 5M");
ErrorCode USER_AVATAR_UPLOAD_FAILED = new ErrorCode(1_002_003_105, "头像上传失败");
// ========== 部门模块 1-002-004-000 ==========
ErrorCode DEPT_NAME_DUPLICATE = new ErrorCode(1_002_004_000, "已经存在该名字的部门");

View File

@@ -1,7 +1,7 @@
package com.njcn.rdms.module.system.controller.admin.user;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.framework.encrypt.core.annotation.ApiEncrypt;
import com.njcn.rdms.module.system.controller.admin.user.vo.profile.UserProfileRespVO;
import com.njcn.rdms.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO;
@@ -9,6 +9,7 @@ import com.njcn.rdms.module.system.controller.admin.user.vo.profile.UserProfileU
import com.njcn.rdms.module.system.convert.user.UserConvert;
import com.njcn.rdms.module.system.dal.dataobject.dept.DeptDO;
import com.njcn.rdms.module.system.dal.dataobject.dept.PostDO;
import com.njcn.rdms.module.system.dal.dataobject.file.FileDO;
import com.njcn.rdms.module.system.dal.dataobject.permission.RoleDO;
import com.njcn.rdms.module.system.dal.dataobject.user.AdminUserDO;
import com.njcn.rdms.module.system.service.dept.DeptService;
@@ -22,11 +23,8 @@ import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@@ -84,4 +82,12 @@ public class UserProfileController {
return success(true);
}
@PutMapping("/update-avatar")
@Operation(summary = "修改用户个人头像")
public CommonResult<FileDO> updateUserAvatar(@RequestParam("file") MultipartFile file) {
// 获得用户基本信息
AdminUserDO user = userService.getUser(getLoginUserId());
FileDO fileDO = userService.uploadAvatar(file, user);
return success(fileDO);
}
}

View File

@@ -10,14 +10,12 @@ import com.njcn.rdms.module.system.controller.admin.user.vo.user.UserImportExcel
import com.njcn.rdms.module.system.controller.admin.user.vo.user.UserImportRespVO;
import com.njcn.rdms.module.system.controller.admin.user.vo.user.UserPageReqVO;
import com.njcn.rdms.module.system.controller.admin.user.vo.user.UserSaveReqVO;
import com.njcn.rdms.module.system.dal.dataobject.file.FileDO;
import com.njcn.rdms.module.system.dal.dataobject.user.AdminUserDO;
import jakarta.validation.Valid;
import org.springframework.web.multipart.MultipartFile;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* 后台用户 Service 接口
@@ -226,7 +224,7 @@ public interface AdminUserService {
/**
* 判断用户当前是否可用
*
* <p>
* 口径:
* 1. `status` 必须为启用
* 2. `resignedAt` 为空,或者晚于当前时间
@@ -252,4 +250,13 @@ public interface AdminUserService {
* @return 可用用户 ID 集合
*/
Set<Long> listEnabledUserIdsByDeptIds(Collection<Long> deptIds);
/**
* 上传头像
*
* @param file
* @param user
* @return
*/
FileDO uploadAvatar(MultipartFile file, AdminUserDO user);
}

View File

@@ -1,8 +1,12 @@
package com.njcn.rdms.module.system.service.user;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.google.common.annotations.VisibleForTesting;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.service.impl.DiffParseFunction;
@@ -23,11 +27,16 @@ import com.njcn.rdms.module.system.controller.admin.user.vo.user.UserPageReqVO;
import com.njcn.rdms.module.system.controller.admin.user.vo.user.UserSaveReqVO;
import com.njcn.rdms.module.system.dal.dataobject.config.ConfigDO;
import com.njcn.rdms.module.system.dal.dataobject.dept.DeptDO;
import com.njcn.rdms.module.system.dal.dataobject.file.FileDO;
import com.njcn.rdms.module.system.dal.dataobject.user.AdminUserDO;
import com.njcn.rdms.module.system.dal.mysql.file.FileMapper;
import com.njcn.rdms.module.system.dal.mysql.user.AdminUserMapper;
import com.njcn.rdms.module.system.framework.file.core.client.FileClient;
import com.njcn.rdms.module.system.framework.file.core.utils.FileTypeUtils;
import com.njcn.rdms.module.system.service.config.ConfigService;
import com.njcn.rdms.module.system.service.dept.DeptService;
import com.njcn.rdms.module.system.service.dept.PostService;
import com.njcn.rdms.module.system.service.file.FileConfigService;
import com.njcn.rdms.module.system.service.oauth2.OAuth2TokenService;
import com.njcn.rdms.module.system.service.permission.PermissionService;
import jakarta.annotation.Resource;
@@ -37,6 +46,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDateTime;
import java.util.*;
@@ -77,6 +87,10 @@ public class AdminUserServiceImpl implements AdminUserService {
private ConfigService configService;
@Resource
private UserManagementRelationService userManagementRelationService;
@Resource
private FileConfigService fileConfigService;
@Resource
private FileMapper fileMapper;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -216,7 +230,7 @@ public class AdminUserServiceImpl implements AdminUserService {
@Transactional(rollbackFor = Exception.class)
public void deleteUserList(List<Long> ids) {
//批量删除前查看是否管理链路表还在使用该用户
for (Long id : ids){
for (Long id : ids) {
Boolean res = userManagementRelationService.hasRelation(id);
if (res) {
throw exception(USER_MANAGEMENT_RELATION_EXISTS);
@@ -513,6 +527,79 @@ public class AdminUserServiceImpl implements AdminUserService {
return getUserListByDeptIds(deptCondition);
}
@Override
public FileDO uploadAvatar(MultipartFile file, AdminUserDO user) {
String type = file.getContentType();
String name = file.getOriginalFilename();
FileDO fileDO = null;
try {
byte[] content = IoUtil.readBytes(file.getInputStream());
// 1.1 处理 type 为空的情况
if (StrUtil.isEmpty(type)) {
type = FileTypeUtils.getMineType(content, name);
}
// 验证文件类型
validateImageFile(file);
// 1.2 处理 name 为空的情况
if (StrUtil.isEmpty(name)) {
name = DigestUtil.sha256Hex(content);
}
if (StrUtil.isEmpty(FileUtil.extName(name))) {
// 如果 name 没有后缀 type则补充后缀
String extension = FileTypeUtils.getExtension(type);
if (StrUtil.isNotEmpty(extension)) {
name = name + extension;
}
}
// 2.1 生成上传的 path需要保证唯一
String path = FileUtil.FILE_SEPARATOR + "rdms\\avatar" + FileUtil.FILE_SEPARATOR + generateUniqueFileName(name);
// 2.2 上传到文件存储器
FileClient client = fileConfigService.getMasterFileClient();
Assert.notNull(client, "客户端(master) 不能为空");
String url = null;
url = client.upload(content, path, type);
//删除旧的
client.delete(user.getAvatar());
// 3. 保存到数据库
fileDO = new FileDO().setConfigId(client.getId())
.setName(name).setPath(path).setUrl(url)
.setType(type).setSize((long) content.length);
fileMapper.insert(fileDO);
user.setAvatar(fileDO.getUrl());
this.userMapper.updateById(user);
} catch (Exception e) {
throw exception(USER_AVATAR_UPLOAD_FAILED);
}
return fileDO;
}
private void validateImageFile(MultipartFile file) {
// 检查文件类型
String contentType = file.getContentType();
if (contentType == null || !contentType.startsWith("image/")) {
throw exception(USER_AVATAR_SUFFIX_ERROR);
}
// 检查文件大小例如限制5MB
if (file.getSize() > 5 * 1024 * 1024) {
throw exception(USER_AVATAR_SIZE_ERROR);
}
}
private String generateUniqueFileName(String originalFilename) {
String extension = "";
if (originalFilename != null && originalFilename.contains(".")) {
extension = originalFilename.substring(originalFilename.lastIndexOf("."));
}
return UUID.randomUUID().toString() + extension;
}
/**
* 对密码进行加密
*