云文件系统初始化

This commit is contained in:
2026-04-01 22:39:11 +08:00
commit 3a20f6e7ed
74 changed files with 8693 additions and 0 deletions

View File

@@ -0,0 +1,112 @@
package com.filesystem.controller;
import com.filesystem.entity.User;
import com.filesystem.security.UserPrincipal;
import com.filesystem.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Resource
private UserService userService;
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody Map<String, String> request) {
String username = request.get("username");
String password = request.get("password");
try {
String token = userService.login(username, password);
User user = userService.findByUsername(username);
// 精确重算存储空间
long storageUsed = userService.recalculateStorage(user.getId());
long storageLimit = user.getStorageLimit() != null ? user.getStorageLimit() : 20L * 1024 * 1024 * 1024;
Map<String, Object> userData = new HashMap<>();
userData.put("id", user.getId());
userData.put("username", user.getUsername());
userData.put("nickname", user.getNickname() != null ? user.getNickname() : "");
userData.put("signature", user.getSignature() != null ? user.getSignature() : "");
userData.put("avatar", user.getAvatar() != null ? user.getAvatar() : "");
userData.put("phone", user.getPhone() != null ? user.getPhone() : "");
userData.put("email", user.getEmail() != null ? user.getEmail() : "");
userData.put("storageUsed", storageUsed);
userData.put("storageLimit", storageLimit);
Map<String, Object> result = new HashMap<>();
result.put("token", token);
result.put("user", userData);
Map<String, Object> body = new HashMap<>();
body.put("data", result);
body.put("message", "登录成功");
return ResponseEntity.ok(body);
} catch (Exception e) {
return ResponseEntity.status(401).body(Map.of("message", e.getMessage()));
}
}
@PostMapping("/register")
public ResponseEntity<?> register(@RequestBody Map<String, String> request) {
String username = request.get("username");
String password = request.get("password");
String nickname = request.get("nickname");
if (userService.findByUsername(username) != null) {
return ResponseEntity.badRequest().body(Map.of("message", "用户名已存在"));
}
User user = userService.createUser(username, password, nickname != null ? nickname : username);
return ResponseEntity.ok(Map.of("message", "注册成功", "data", Map.of("id", user.getId())));
}
@PostMapping("/logout")
public ResponseEntity<?> logout(@AuthenticationPrincipal UserPrincipal principal) {
if (principal != null) {
userService.logout(principal.getUserId());
}
return ResponseEntity.ok(Map.of("message", "退出成功"));
}
@GetMapping("/info")
public ResponseEntity<?> getUserInfo(@AuthenticationPrincipal UserPrincipal principal) {
if (principal == null) {
return ResponseEntity.status(401).body(Map.of("message", "未登录"));
}
User user = userService.findById(principal.getUserId());
if (user == null) {
return ResponseEntity.status(401).body(Map.of("message", "用户不存在"));
}
// 精确重算存储空间
long storageUsed = userService.recalculateStorage(user.getId());
long storageLimit = user.getStorageLimit() != null ? user.getStorageLimit() : 20L * 1024 * 1024 * 1024;
Map<String, Object> userData = new HashMap<>();
userData.put("id", user.getId());
userData.put("username", user.getUsername());
userData.put("nickname", user.getNickname() != null ? user.getNickname() : "");
userData.put("signature", user.getSignature() != null ? user.getSignature() : "");
userData.put("avatar", user.getAvatar() != null ? user.getAvatar() : "");
userData.put("email", user.getEmail() != null ? user.getEmail() : "");
userData.put("phone", user.getPhone() != null ? user.getPhone() : "");
userData.put("storageUsed", storageUsed);
userData.put("storageLimit", storageLimit);
Map<String, Object> body = new HashMap<>();
body.put("data", userData);
return ResponseEntity.ok(body);
}
}

View File

@@ -0,0 +1,254 @@
package com.filesystem.controller;
import com.filesystem.entity.FileEntity;
import com.filesystem.entity.FileShare;
import com.filesystem.security.UserPrincipal;
import com.filesystem.service.FileService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/files")
public class FileController {
@Resource
private FileService fileService;
@Value("${file.storage.path:./uploads}")
private String storagePath;
public FileController() {
}
@GetMapping("/test")
public ResponseEntity<?> test() {
return ResponseEntity.ok(Map.of("message", "Backend is running", "timestamp", System.currentTimeMillis()));
}
@GetMapping
public ResponseEntity<?> getFiles(
@AuthenticationPrincipal UserPrincipal principal,
@RequestParam(required = false) Long folderId,
@RequestParam(required = false) String keyword) {
List<FileEntity> files = fileService.getFiles(principal.getUserId(), folderId, keyword);
return ResponseEntity.ok(Map.of("data", files));
}
@GetMapping("/trashFiles")
public ResponseEntity<?> getTrashFiles(
@AuthenticationPrincipal UserPrincipal principal,
@RequestParam(required = false) Long folderId) {
return ResponseEntity.ok(Map.of("data", fileService.getTrashFiles(principal.getUserId(), folderId)));
}
@GetMapping("/sharedByMe")
public ResponseEntity<?> getSharedByMe(@AuthenticationPrincipal UserPrincipal principal) {
return ResponseEntity.ok(Map.of("data", fileService.getSharedByMe(principal.getUserId())));
}
@GetMapping("/sharedByMe/folder")
public ResponseEntity<?> getSharedByMeFolderFiles(
@AuthenticationPrincipal UserPrincipal principal,
@RequestParam Long folderId) {
List<FileEntity> files = fileService.getSharedByMeFolderFiles(principal.getUserId(), folderId);
return ResponseEntity.ok(Map.of("data", files));
}
@GetMapping("/sharedToMe")
public ResponseEntity<?> getSharedToMe(@AuthenticationPrincipal UserPrincipal principal) {
return ResponseEntity.ok(Map.of("data", fileService.getSharedToMe(principal.getUserId())));
}
@GetMapping("/sharedToMe/folder")
public ResponseEntity<?> getSharedFolderFiles(
@AuthenticationPrincipal UserPrincipal principal,
@RequestParam Long folderId) {
List<FileEntity> files = fileService.getSharedFolderFiles(principal.getUserId(), folderId);
return ResponseEntity.ok(Map.of("data", files));
}
@PostMapping("/uploadBatch")
public ResponseEntity<?> uploadFiles(
@AuthenticationPrincipal UserPrincipal principal,
@RequestParam("files") List<MultipartFile> files,
@RequestParam(required = false) Long folderId) throws IOException {
List<FileEntity> uploaded = fileService.uploadFiles(files, principal.getUserId(), folderId);
return ResponseEntity.ok(Map.of("data", uploaded, "message", "上传成功"));
}
@PostMapping("/createFolder")
public ResponseEntity<?> createFolder(
@AuthenticationPrincipal UserPrincipal principal,
@RequestBody Map<String, Object> request) {
String name = (String) request.get("name");
Long parentId = request.get("parentId") != null ? Long.valueOf(request.get("parentId").toString()) : null;
FileEntity folder = fileService.createFolder(name, principal.getUserId(), parentId);
return ResponseEntity.ok(Map.of("data", folder, "message", "创建成功"));
}
@DeleteMapping("/{id}")
public ResponseEntity<?> deleteFile(
@AuthenticationPrincipal UserPrincipal principal,
@PathVariable Long id) {
fileService.moveToTrash(id, principal.getUserId());
return ResponseEntity.ok(Map.of("message", "已移至回收站"));
}
@PostMapping("/{id}/restore")
public ResponseEntity<?> restoreFile(
@AuthenticationPrincipal UserPrincipal principal,
@PathVariable Long id) {
fileService.restoreFile(id, principal.getUserId());
return ResponseEntity.ok(Map.of("message", "已还原"));
}
@DeleteMapping("/{id}/deletePermanent")
public ResponseEntity<?> deletePermanently(
@AuthenticationPrincipal UserPrincipal principal,
@PathVariable Long id) {
fileService.deletePermanently(id, principal.getUserId());
return ResponseEntity.ok(Map.of("message", "已彻底删除"));
}
@DeleteMapping("/emptyTrash")
public ResponseEntity<?> emptyTrash(@AuthenticationPrincipal UserPrincipal principal) {
fileService.emptyTrash(principal.getUserId());
return ResponseEntity.ok(Map.of("message", "已清空回收站"));
}
@GetMapping("/{id}/download")
public ResponseEntity<byte[]> downloadFile(
@AuthenticationPrincipal UserPrincipal principal,
@PathVariable Long id) throws IOException {
FileEntity file = fileService.getById(id);
if (file == null) return ResponseEntity.notFound().build();
byte[] content = fileService.getFileContent(file);
if (content == null) return ResponseEntity.notFound().build();
String encodedName = URLEncoder.encode(file.getName(), StandardCharsets.UTF_8).replace("+", "%20");
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedName + "\"")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(content);
}
@GetMapping("/{id}/preview")
public ResponseEntity<byte[]> previewFile(
@AuthenticationPrincipal UserPrincipal principal,
@PathVariable Long id) throws IOException {
FileEntity file = fileService.getById(id);
if (file == null) return ResponseEntity.notFound().build();
byte[] content = fileService.getFileContent(file);
if (content == null) return ResponseEntity.notFound().build();
String encodedName = URLEncoder.encode(file.getName(), StandardCharsets.UTF_8).replace("+", "%20");
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + encodedName + "\"")
.contentType(getMediaType(file.getName()))
.body(content);
}
@PostMapping("/{id}/shareFile")
public ResponseEntity<?> shareFile(
@AuthenticationPrincipal UserPrincipal principal,
@PathVariable Long id,
@RequestBody Map<String, Object> request) {
Long shareToUserId = Long.valueOf(request.get("userId").toString());
String permission = (String) request.getOrDefault("permission", "view");
FileShare share = fileService.shareFile(id, principal.getUserId(), shareToUserId, permission);
return ResponseEntity.ok(Map.of("data", share, "message", "共享成功"));
}
@DeleteMapping("/{id}/cancelShare")
public ResponseEntity<?> cancelShare(
@AuthenticationPrincipal UserPrincipal principal,
@PathVariable Long id) {
fileService.cancelShare(id, principal.getUserId());
return ResponseEntity.ok(Map.of("message", "已取消共享"));
}
/**
* 获取头像图片
*/
@GetMapping("/avatar/**")
public ResponseEntity<byte[]> getAvatar(jakarta.servlet.http.HttpServletRequest request) throws IOException {
String uri = request.getRequestURI();
String prefix = "/api/files/avatar/";
String relativePath = uri.substring(uri.indexOf(prefix) + prefix.length());
// relativePath = "2026/04/xxx.jpg"
Path filePath = Paths.get(storagePath).toAbsolutePath().resolve("avatars").resolve(relativePath);
if (!Files.exists(filePath)) {
return ResponseEntity.notFound().build();
}
byte[] content = Files.readAllBytes(filePath);
String fileName = relativePath.contains("/") ? relativePath.substring(relativePath.lastIndexOf("/") + 1) : relativePath;
String ext = fileName.contains(".") ? fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase() : "jpg";
String contentType = switch (ext) {
case "png" -> "image/png";
case "gif" -> "image/gif";
case "webp" -> "image/webp";
default -> "image/jpeg";
};
return ResponseEntity.ok()
.contentType(org.springframework.http.MediaType.parseMediaType(contentType))
.header(HttpHeaders.CACHE_CONTROL, "max-age=86400")
.body(content);
}
private MediaType getMediaType(String filename) {
String ext = filename.contains(".") ? filename.substring(filename.lastIndexOf(".")).toLowerCase() : "";
return switch (ext) {
case ".jpg", ".jpeg" -> MediaType.IMAGE_JPEG;
case ".png" -> MediaType.IMAGE_PNG;
case ".gif" -> MediaType.IMAGE_GIF;
case ".pdf" -> MediaType.APPLICATION_PDF;
default -> MediaType.APPLICATION_OCTET_STREAM;
};
}
@PutMapping("/{id}/rename")
public ResponseEntity<?> renameFile(
@AuthenticationPrincipal UserPrincipal principal,
@PathVariable Long id,
@RequestBody Map<String, String> request) {
String newName = request.get("name");
if (newName == null || newName.trim().isEmpty()) {
return ResponseEntity.badRequest().body(Map.of("message", "名称不能为空"));
}
try {
fileService.renameFile(id, principal.getUserId(), newName.trim());
return ResponseEntity.ok(Map.of("message", "重命名成功"));
} catch (RuntimeException e) {
return ResponseEntity.badRequest().body(Map.of("message", e.getMessage()));
}
}
@PutMapping("/{id}/move")
public ResponseEntity<?> moveFile(
@AuthenticationPrincipal UserPrincipal principal,
@PathVariable Long id,
@RequestBody Map<String, Long> request) {
Long folderId = request.get("folderId");
try {
fileService.moveFile(id, principal.getUserId(), folderId);
return ResponseEntity.ok(Map.of("message", "移动成功"));
} catch (RuntimeException e) {
return ResponseEntity.badRequest().body(Map.of("message", e.getMessage()));
}
}
}
}

View File

@@ -0,0 +1,279 @@
package com.filesystem.controller;
import com.filesystem.entity.Message;
import com.filesystem.entity.User;
import com.filesystem.security.UserPrincipal;
import com.filesystem.service.MessageService;
import com.filesystem.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.LinkedHashMap;
@RestController
@RequestMapping("/api/messages")
public class MessageController {
@Resource
private MessageService messageService;
@Resource
private UserService userService;
@Value("${file.storage.path:./uploads}")
private String storagePath;
private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy/MM");
// ==================== 聊天文件上传 ====================
@PostMapping("/upload")
public ResponseEntity<?> uploadChatFile(
@AuthenticationPrincipal UserPrincipal principal,
@RequestParam("file") MultipartFile file) throws IOException {
if (file.isEmpty()) {
return ResponseEntity.badRequest().body(Map.of("message", "请选择文件"));
}
String originalName = file.getOriginalFilename();
String ext = originalName != null && originalName.contains(".")
? originalName.substring(originalName.lastIndexOf(".")) : "";
String storedName = UUID.randomUUID().toString() + ext;
String datePath = LocalDateTime.now().format(DATE_FMT);
Path targetDir = Paths.get(storagePath).toAbsolutePath().resolve("chat").resolve(datePath);
if (!Files.exists(targetDir)) {
Files.createDirectories(targetDir);
}
Path filePath = targetDir.resolve(storedName);
file.transferTo(filePath.toFile());
String fileUrl = "/api/messages/file/" + datePath + "/" + storedName;
return ResponseEntity.ok(Map.of("url", fileUrl, "message", "上传成功"));
}
// ==================== 聊天文件访问 ====================
@GetMapping("/file/**")
public ResponseEntity<byte[]> getChatFile(HttpServletRequest request) throws IOException {
String uri = request.getRequestURI();
String prefix = "/api/messages/file/";
String relativePath = uri.substring(uri.indexOf(prefix) + prefix.length());
// relativePath = "2026/04/xxx.jpg"
int lastSlash = relativePath.lastIndexOf('/');
String datePath = relativePath.substring(0, lastSlash);
String fileName = relativePath.substring(lastSlash + 1);
Path filePath = Paths.get(storagePath).toAbsolutePath()
.resolve("chat").resolve(datePath).resolve(fileName);
if (!Files.exists(filePath)) {
return ResponseEntity.notFound().build();
}
byte[] content = Files.readAllBytes(filePath);
String ext = fileName.contains(".") ? fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase() : "";
boolean isImage = Set.of("png", "jpg", "jpeg", "gif", "webp", "bmp", "svg").contains(ext);
String contentType = switch (ext) {
case "pdf" -> "application/pdf";
case "png" -> "image/png";
case "gif" -> "image/gif";
case "webp" -> "image/webp";
case "jpg", "jpeg" -> "image/jpeg";
case "bmp" -> "image/bmp";
case "svg" -> "image/svg+xml";
default -> "application/octet-stream";
};
String encodedName = URLEncoder.encode(fileName, StandardCharsets.UTF_8).replace("+", "%20");
String disposition = isImage
? "inline; filename=\"" + encodedName + "\""
: "attachment; filename=\"" + encodedName + "\"";
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(contentType))
.header(HttpHeaders.CONTENT_DISPOSITION, disposition)
.header(HttpHeaders.CACHE_CONTROL, "max-age=86400")
.body(content);
}
// ==================== 消息收发 ====================
@GetMapping
public ResponseEntity<?> getMessages(
@AuthenticationPrincipal UserPrincipal principal,
@RequestParam Long userId) {
List<Message> messages = messageService.getMessages(principal.getUserId(), userId);
for (Message msg : messages) {
if (msg.getToUserId().equals(principal.getUserId()) && msg.getIsRead() == 0) {
msg.setIsRead(1);
messageService.updateMessage(msg);
}
}
Set<Long> userIds = new HashSet<>();
userIds.add(principal.getUserId());
userIds.add(userId);
for (Message msg : messages) {
userIds.add(msg.getFromUserId());
userIds.add(msg.getToUserId());
}
Map<Long, User> userMap = new HashMap<>();
for (Long uid : userIds) {
User u = userService.findById(uid);
if (u != null) userMap.put(uid, u);
}
List<Map<String, Object>> result = messages.stream().map(msg -> {
Map<String, Object> m = new HashMap<>();
m.put("id", msg.getId());
m.put("fromUserId", msg.getFromUserId());
m.put("toUserId", msg.getToUserId());
m.put("content", msg.getContent());
m.put("type", msg.getType());
m.put("fileName", msg.getFileName());
m.put("fileSize", msg.getFileSize());
m.put("isRead", msg.getIsRead());
m.put("createTime", msg.getCreateTime() != null ? msg.getCreateTime().toString() : "");
User fromUser = userMap.get(msg.getFromUserId());
if (fromUser != null) {
m.put("fromUsername", fromUser.getUsername());
m.put("fromNickname", fromUser.getNickname() != null ? fromUser.getNickname() : fromUser.getUsername());
m.put("fromAvatar", fromUser.getAvatar());
m.put("fromSignature", fromUser.getSignature());
}
return m;
}).collect(Collectors.toList());
return ResponseEntity.ok(Map.of("data", result));
}
@GetMapping("/users")
public ResponseEntity<?> getUsers(@AuthenticationPrincipal UserPrincipal principal) {
List<User> users = userService.getAllUsersExcept(principal.getUserId());
List<Map<String, Object>> result = users.stream()
.map(u -> {
Map<String, Object> m = new HashMap<>();
m.put("id", u.getId());
m.put("username", u.getUsername());
m.put("nickname", u.getNickname() != null ? u.getNickname() : u.getUsername());
m.put("avatar", u.getAvatar());
m.put("signature", u.getSignature());
m.put("email", u.getEmail());
m.put("phone", u.getPhone());
return m;
})
.collect(Collectors.toList());
return ResponseEntity.ok(Map.of("data", result));
}
@PostMapping
public ResponseEntity<?> sendMessage(
@AuthenticationPrincipal UserPrincipal principal,
@RequestBody Map<String, Object> request) {
Long toUserId = Long.valueOf(request.get("toUserId").toString());
String content = (String) request.get("content");
String type = (String) request.getOrDefault("type", "text");
String fileName = (String) request.get("fileName");
Object fileSizeObj = request.get("fileSize");
Long fileSize = fileSizeObj != null ? Long.valueOf(fileSizeObj.toString()) : null;
Message message = messageService.sendMessage(principal.getUserId(), toUserId, content, type);
if (("file".equals(type) || "image".equals(type)) && fileName != null) {
message.setFileName(fileName);
message.setFileSize(fileSize);
messageService.updateMessage(message);
}
Map<String, Object> result = new HashMap<>();
result.put("id", message.getId());
result.put("fromUserId", message.getFromUserId());
result.put("toUserId", message.getToUserId());
result.put("content", message.getContent());
result.put("type", message.getType());
result.put("fileName", message.getFileName());
result.put("fileSize", message.getFileSize());
result.put("createTime", message.getCreateTime() != null ? message.getCreateTime().toString() : "");
User fromUser = userService.findById(principal.getUserId());
if (fromUser != null) {
result.put("fromUsername", fromUser.getUsername());
result.put("fromNickname", fromUser.getNickname() != null ? fromUser.getNickname() : fromUser.getUsername());
result.put("fromSignature", fromUser.getSignature());
}
return ResponseEntity.ok(Map.of("data", result, "message", "发送成功"));
}
@GetMapping("/unreadCount")
public ResponseEntity<?> getUnreadCount(@AuthenticationPrincipal UserPrincipal principal) {
int count = messageService.getUnreadCount(principal.getUserId());
return ResponseEntity.ok(Map.of("data", Map.of("count", count)));
}
@GetMapping("/unreadList")
public ResponseEntity<?> getUnreadList(@AuthenticationPrincipal UserPrincipal principal) {
List<Message> unreadMessages = messageService.getUnreadMessages(principal.getUserId());
// 按发送人分组
Map<Long, List<Message>> grouped = unreadMessages.stream()
.collect(Collectors.groupingBy(Message::getFromUserId, LinkedHashMap::new, Collectors.toList()));
List<Map<String, Object>> result = new ArrayList<>();
for (Map.Entry<Long, List<Message>> entry : grouped.entrySet()) {
Long fromUserId = entry.getKey();
List<Message> msgs = entry.getValue();
Message lastMsg = msgs.get(0); // 已按时间倒序,第一条就是最新的
User fromUser = userService.findById(fromUserId);
Map<String, Object> item = new HashMap<>();
item.put("userId", fromUserId);
item.put("unread", msgs.size());
item.put("lastMsg", lastMsg.getType() != null && lastMsg.getType().startsWith("image")
? "[图片]" : (lastMsg.getType() != null && lastMsg.getType().equals("file")
? "[文件]" : (lastMsg.getContent() != null && lastMsg.getContent().length() > 30
? lastMsg.getContent().substring(0, 30) + "..." : lastMsg.getContent())));
item.put("lastTime", lastMsg.getCreateTime() != null ? lastMsg.getCreateTime().toString() : "");
if (fromUser != null) {
item.put("username", fromUser.getUsername());
item.put("nickname", fromUser.getNickname() != null ? fromUser.getNickname() : fromUser.getUsername());
item.put("avatar", fromUser.getAvatar());
item.put("signature", fromUser.getSignature());
}
result.add(item);
}
return ResponseEntity.ok(Map.of("data", result));
}
@PostMapping("/{id}/read")
public ResponseEntity<?> markAsRead(@PathVariable Long id) {
messageService.markAsRead(id);
return ResponseEntity.ok(Map.of("message", "已标记已读"));
}
}

View File

@@ -0,0 +1,125 @@
package com.filesystem.controller;
import com.filesystem.entity.User;
import com.filesystem.security.UserPrincipal;
import com.filesystem.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
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.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/users")
public class UserController {
@Resource
private UserService userService;
@Value("${file.storage.path:./uploads}")
private String storagePath;
/**
* 获取所有可用用户(用于文件共享等场景)
*/
@GetMapping
public ResponseEntity<?> getAllUsers(@AuthenticationPrincipal UserPrincipal principal) {
List<User> users = userService.getAllUsersExcept(principal.getUserId());
List<Map<String, Object>> result = users.stream()
.filter(u -> u.getStatus() == 1) // 只返回启用状态的用户
.map(u -> {
Map<String, Object> m = new java.util.HashMap<>();
m.put("id", u.getId());
m.put("username", u.getUsername());
m.put("nickname", u.getNickname() != null ? u.getNickname() : u.getUsername());
m.put("avatar", u.getAvatar());
m.put("signature", u.getSignature());
return m;
})
.collect(Collectors.toList());
return ResponseEntity.ok(Map.of("data", result));
}
/**
* 上传头像
*/
@PostMapping("/avatar")
public ResponseEntity<?> uploadAvatar(
@AuthenticationPrincipal UserPrincipal principal,
@RequestParam("avatar") MultipartFile file) throws IOException {
if (file.isEmpty()) {
return ResponseEntity.badRequest().body(Map.of("message", "请选择图片"));
}
// 限制文件大小 2MB
if (file.getSize() > 2 * 1024 * 1024) {
return ResponseEntity.badRequest().body(Map.of("message", "图片大小不能超过2MB"));
}
// 保存文件
String originalFilename = file.getOriginalFilename();
String ext = originalFilename != null && originalFilename.contains(".")
? originalFilename.substring(originalFilename.lastIndexOf("."))
: ".jpg";
String fileName = UUID.randomUUID().toString() + ext;
String datePath = java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy/MM"));
// 使用配置文件中的路径 + 日期目录
Path uploadPath = Paths.get(storagePath).toAbsolutePath().resolve("avatars").resolve(datePath);
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
Path filePath = uploadPath.resolve(fileName);
Files.copy(file.getInputStream(), filePath);
// 更新用户头像
String avatarUrl = "/api/files/avatar/" + datePath + "/" + fileName;
userService.updateAvatar(principal.getUserId(), avatarUrl);
return ResponseEntity.ok(Map.of("data", Map.of("url", avatarUrl), "message", "上传成功"));
}
/**
* 获取当前用户信息
*/
@GetMapping("/me")
public ResponseEntity<?> getCurrentUser(@AuthenticationPrincipal UserPrincipal principal) {
User user = userService.findById(principal.getUserId());
Map<String, Object> result = new java.util.HashMap<>();
result.put("id", user.getId());
result.put("username", user.getUsername());
result.put("nickname", user.getNickname());
result.put("avatar", user.getAvatar());
result.put("signature", user.getSignature());
result.put("email", user.getEmail());
result.put("phone", user.getPhone());
return ResponseEntity.ok(Map.of("data", result));
}
/**
* 更新个人信息
*/
@PutMapping("/profile")
public ResponseEntity<?> updateProfile(
@AuthenticationPrincipal UserPrincipal principal,
@RequestBody Map<String, String> request) {
String nickname = request.get("nickname");
String signature = request.get("signature");
String phone = request.get("phone");
String email = request.get("email");
userService.updateProfile(principal.getUserId(), nickname, signature, phone, email);
return ResponseEntity.ok(Map.of("message", "更新成功"));
}
}