用户头像

Change-Id: I562c0cb7212c1ac9c7ad1dad96b136fc8c23269c
diff --git a/src/main/java/com/example/myproject/controller/UserController.java b/src/main/java/com/example/myproject/controller/UserController.java
index 224c138..6b3d793 100644
--- a/src/main/java/com/example/myproject/controller/UserController.java
+++ b/src/main/java/com/example/myproject/controller/UserController.java
@@ -6,8 +6,11 @@
 import com.example.myproject.service.TaskService;
 import com.example.myproject.service.UserService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.http.HttpServletRequest;
 import java.util.Map;
 import java.util.Optional;
 
@@ -103,14 +106,13 @@
             @RequestBody Map<String, Object> profileData) {
 
         // 获取请求体中的修改数据
-        String avatarUrl = (String) profileData.get("avatarUrl");
         String nickname = (String) profileData.get("nickname");
         String gender = (String) profileData.get("gender");
         String description = (String) profileData.get("description");
         String hobbies = (String) profileData.get("hobbies");
 
         // 调用服务层方法进行修改
-        boolean updated = userService.editProfile(userId, avatarUrl, nickname, gender, description, hobbies);
+        boolean updated = userService.editProfile(userId, nickname, gender, description, hobbies);
 
         // 返回操作结果消息
         if (updated) {
@@ -149,6 +151,14 @@
         return friends;
     }
 
+    @PostMapping("/{userId}/uploadAvatar")
+    public Map<String, Object> uploadAvatar(
+            @PathVariable Long userId,
+            @RequestParam("file") MultipartFile file) {
+        return userService.uploadUserAvatar(userId, file);
+    }
+
+
 
 }
 
diff --git a/src/main/java/com/example/myproject/repository/UserRepository.java b/src/main/java/com/example/myproject/repository/UserRepository.java
index 6927c5f..c61a79a 100644
--- a/src/main/java/com/example/myproject/repository/UserRepository.java
+++ b/src/main/java/com/example/myproject/repository/UserRepository.java
@@ -6,5 +6,6 @@
 
 public interface UserRepository extends JpaRepository<Users, Long> {
     Optional<Users> findByEmail(String email);
+
     Optional<Users> findByUsername(String username);
 }
diff --git a/src/main/java/com/example/myproject/service/UserService.java b/src/main/java/com/example/myproject/service/UserService.java
index 0d37854..283a85c 100644
--- a/src/main/java/com/example/myproject/service/UserService.java
+++ b/src/main/java/com/example/myproject/service/UserService.java
@@ -1,12 +1,21 @@
 package com.example.myproject.service;
 
+import com.example.myproject.entity.User;
 import com.example.myproject.entity.Users;
 import com.example.myproject.entity.UserInviteCode;
 import com.example.myproject.repository.UserRepository;
 import com.example.myproject.repository.UserInviteCodeRepository;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.LocalDateTime;
 import java.util.*;
 
 @Service
@@ -207,7 +216,7 @@
     }
 
     // 修改用户个人资料
-    public boolean editProfile(Long userId, String avatarUrl, String nickname, String gender, String description, String hobbies) {
+    public boolean editProfile(Long userId, String nickname, String gender, String description, String hobbies) {
         Optional<Users> userOptional = userRepository.findById(userId);
 
         // 如果用户不存在,返回false
@@ -218,9 +227,6 @@
         Users user = userOptional.get();
 
         // 更新用户资料,只有传入值才会更新对应字段
-        if (avatarUrl != null) {
-            user.setAvatarUrl(avatarUrl);
-        }
         if (nickname != null) {
             user.setUsername(nickname);
         }
@@ -266,4 +272,40 @@
     }
 
 
+    private static final String AVATAR_DIR = "uploads/avatarUrl/";
+
+    public Map<String, Object> uploadUserAvatar(Long userId, MultipartFile file) {
+        Users user = userRepository.findById(userId)
+                .orElseThrow(() -> new RuntimeException("用户不存在"));
+
+        try {
+            String avatarUrl = saveAvatar(file, userId);
+            user.setAvatarUrl(avatarUrl);
+            userRepository.save(user);
+
+            Map<String, Object> response = new HashMap<>();
+            response.put("status", "success");
+            response.put("message", "头像上传成功");
+            response.put("userId", user.getUserId());
+            response.put("avatarUrl", avatarUrl);
+            return response;
+
+        } catch (IOException e) {
+            throw new RuntimeException("头像上传失败: " + e.getMessage());
+        }
+    }
+
+    // 保存头像文件并返回可访问 URL
+    public String saveAvatar(MultipartFile file, Long userId) throws IOException {
+        String originalFilename = file.getOriginalFilename();
+        String extension = originalFilename.substring(originalFilename.lastIndexOf('.'));
+        String fileName = userId + extension;  // 以用户ID作为文件名
+        Path path = Paths.get(AVATAR_DIR + fileName);
+        Files.createDirectories(path.getParent());
+        Files.write(path, file.getBytes());
+        return "/" + AVATAR_DIR + fileName;  // 返回相对URL路径
+    }
+
+
+
 }
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index b878c88..b21068f 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,7 +1,7 @@
 server.port=8080
-spring.datasource.url=jdbc:mysql://localhost:3306/ptProject
-spring.datasource.username=root
-spring.datasource.password=123456
+spring.datasource.url=jdbc:mysql://202.205.102.121:3306/echodevelop
+spring.datasource.username=team11
+spring.datasource.password=Team11000#
 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
 spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
 
diff --git a/src/test/java/com/example/myproject/controller/UserControllerTest.java b/src/test/java/com/example/myproject/controller/UserControllerTest.java
index a97e169..9fd65d9 100644
--- a/src/test/java/com/example/myproject/controller/UserControllerTest.java
+++ b/src/test/java/com/example/myproject/controller/UserControllerTest.java
@@ -8,6 +8,7 @@
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.springframework.mock.web.MockMultipartFile;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -186,14 +187,13 @@
     void testEditProfile() {
         Long userId = 1L;
         Map<String, Object> profileData = new HashMap<>();
-        profileData.put("avatarUrl", "https://example.com/avatar.jpg");
         profileData.put("nickname", "newNickname");
         profileData.put("gender", "Male");
         profileData.put("description", "Updated description");
         profileData.put("hobbies", "Reading, Hiking");
 
         // 模拟服务层的返回
-        when(userService.editProfile(userId, "https://example.com/avatar.jpg", "newNickname", "Male", "Updated description", "Reading, Hiking"))
+        when(userService.editProfile(userId, "newNickname", "Male", "Updated description", "Reading, Hiking"))
                 .thenReturn(true);
 
         // 调用控制器方法
@@ -203,7 +203,7 @@
         assertEquals("用户资料更新成功", resultMap.get("message"));
 
         // 验证服务层方法是否被调用
-        verify(userService, times(1)).editProfile(userId, "https://example.com/avatar.jpg", "newNickname", "Male", "Updated description", "Reading, Hiking");
+        verify(userService, times(1)).editProfile(userId,  "newNickname", "Male", "Updated description", "Reading, Hiking");
     }
 
     @Test
@@ -231,4 +231,37 @@
         assertEquals(expectedResponse, result);
         verify(userService, times(1)).calculateShareRate(userId);  // 验证服务方法是否被调用
     }
+
+    @Test
+    void testUploadUserAvatar() throws Exception {
+        Long userId = 1L;
+
+        // 构造 Mock 文件
+        MockMultipartFile mockFile = new MockMultipartFile(
+                "file",
+                "avatar.jpg",
+                "image/jpeg",
+                "fake image content".getBytes()
+        );
+
+        // 构造返回值
+        Map<String, Object> mockResponse = new HashMap<>();
+        mockResponse.put("status", "success");
+        mockResponse.put("message", "头像上传成功");
+        mockResponse.put("userId", userId);
+        mockResponse.put("avatarUrl", "/uploads/avatarUrl/1.jpg");
+
+        when(userService.uploadUserAvatar(userId, mockFile)).thenReturn(mockResponse);
+
+        Map<String, Object> resultMap = userController.uploadAvatar(userId, mockFile);
+        assertEquals("success", resultMap.get("status"));
+        assertEquals("头像上传成功", resultMap.get("message"));
+        assertEquals(userId, resultMap.get("userId"));
+        assertEquals("/uploads/avatarUrl/1.jpg", resultMap.get("avatarUrl"));
+
+        // 验证 service 被调用一次
+        verify(userService, times(1)).uploadUserAvatar(userId, mockFile);
+    }
+
+
 }