云文件系统初始化
This commit is contained in:
112
src/main/java/com/filesystem/controller/AuthController.java
Normal file
112
src/main/java/com/filesystem/controller/AuthController.java
Normal 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);
|
||||
}
|
||||
}
|
||||
254
src/main/java/com/filesystem/controller/FileController.java
Normal file
254
src/main/java/com/filesystem/controller/FileController.java
Normal 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
279
src/main/java/com/filesystem/controller/MessageController.java
Normal file
279
src/main/java/com/filesystem/controller/MessageController.java
Normal 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", "已标记已读"));
|
||||
}
|
||||
}
|
||||
125
src/main/java/com/filesystem/controller/UserController.java
Normal file
125
src/main/java/com/filesystem/controller/UserController.java
Normal 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", "更新成功"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user