feat: 个人信息修改
This commit is contained in:
@@ -13,6 +13,13 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 用户服务实现
|
||||
@@ -22,6 +29,15 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@RequiredArgsConstructor
|
||||
public class UserServiceImpl implements UserService {
|
||||
|
||||
/** 头像存储目录(相对于项目工作目录) */
|
||||
private static final String AVATAR_DIR = "uploads/avatars";
|
||||
/** 允许的头像文件类型 */
|
||||
private static final Set<String> ALLOWED_CONTENT_TYPES = Set.of(
|
||||
"image/jpeg", "image/png", "image/webp", "image/gif"
|
||||
);
|
||||
/** 头像文件大小上限(2MB) */
|
||||
private static final long MAX_AVATAR_SIZE = 2 * 1024 * 1024;
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
@Override
|
||||
@@ -74,4 +90,84 @@ public class UserServiceImpl implements UserService {
|
||||
userRepository.save(user);
|
||||
log.info("[用户服务] 更新在线状态, accountId={}, status={}", accountId, request.status());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public UserInfoResponse uploadAvatar(String accountId, MultipartFile file) {
|
||||
// 校验文件类型
|
||||
String contentType = file.getContentType();
|
||||
if (contentType == null || !ALLOWED_CONTENT_TYPES.contains(contentType)) {
|
||||
throw new BusinessException(ErrorCode.AVATAR_INVALID_TYPE);
|
||||
}
|
||||
|
||||
// 校验文件大小
|
||||
if (file.getSize() > MAX_AVATAR_SIZE) {
|
||||
throw new BusinessException(ErrorCode.AVATAR_TOO_LARGE);
|
||||
}
|
||||
|
||||
UserEntity user = userRepository.findByAccountId(accountId)
|
||||
.orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));
|
||||
|
||||
try {
|
||||
// 确保目录存在
|
||||
Path avatarDir = Paths.get(AVATAR_DIR);
|
||||
Files.createDirectories(avatarDir);
|
||||
|
||||
// 删除旧头像文件(如果存在且不是默认 SVG)
|
||||
deleteOldAvatarFile(user.getAvatar());
|
||||
|
||||
// 保存新头像:uploads/avatars/{accountId}.jpg
|
||||
String filename = accountId + ".jpg";
|
||||
Path targetPath = avatarDir.resolve(filename);
|
||||
file.transferTo(targetPath.toFile());
|
||||
|
||||
// 更新数据库
|
||||
String avatarUrl = "/" + AVATAR_DIR + "/" + filename;
|
||||
user.setAvatar(avatarUrl);
|
||||
userRepository.save(user);
|
||||
|
||||
log.info("[用户服务] 头像上传成功, accountId={}, path={}", accountId, avatarUrl);
|
||||
return UserInfoResponse.from(user);
|
||||
} catch (IOException e) {
|
||||
log.error("[用户服务] 头像上传失败, accountId={}", accountId, e);
|
||||
throw new BusinessException(ErrorCode.AVATAR_UPLOAD_FAILED, "头像保存失败,请重试");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public UserInfoResponse deleteAvatar(String accountId) {
|
||||
UserEntity user = userRepository.findByAccountId(accountId)
|
||||
.orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));
|
||||
|
||||
// 删除旧头像文件
|
||||
deleteOldAvatarFile(user.getAvatar());
|
||||
|
||||
// 数据库置空(前端会回退显示默认头像)
|
||||
user.setAvatar(null);
|
||||
userRepository.save(user);
|
||||
|
||||
log.info("[用户服务] 头像已删除, accountId={}", accountId);
|
||||
return UserInfoResponse.from(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除旧的用户头像文件
|
||||
*
|
||||
* 仅删除 uploads/avatars/ 下的文件,跳过默认 SVG 和非本地路径。
|
||||
*
|
||||
* @param avatarPath 头像路径,可能为 null
|
||||
*/
|
||||
private void deleteOldAvatarFile(String avatarPath) {
|
||||
if (avatarPath == null || !avatarPath.startsWith("/" + AVATAR_DIR + "/")) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Path oldFile = Paths.get(avatarPath.substring(1)); // 去掉开头的 /
|
||||
Files.deleteIfExists(oldFile);
|
||||
log.debug("[用户服务] 旧头像已删除: {}", oldFile);
|
||||
} catch (IOException e) {
|
||||
log.warn("[用户服务] 旧头像删除失败: {}", avatarPath, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user