Merge "图片配置,帖子替换"
diff --git a/.idea/dataSources.local.xml b/.idea/dataSources.local.xml
index 17c4aa0..370f64a 100644
--- a/.idea/dataSources.local.xml
+++ b/.idea/dataSources.local.xml
@@ -5,7 +5,6 @@
       <database-info product="MySQL" version="8.0.40" jdbc-version="4.2" driver-name="MySQL Connector/J" driver-version="mysql-connector-j-8.2.0 (Revision: 06a1f724497fd81c6a659131fda822c9e5085b6c)" dbms="MYSQL" exact-version="8.0.40" exact-driver-version="8.2">
         <extra-name-characters>#@</extra-name-characters>
         <identifier-quote-string>`</identifier-quote-string>
-        <jdbc-catalog-is-schema>true</jdbc-catalog-is-schema>
       </database-info>
       <case-sensitivity plain-identifiers="lower" quoted-identifiers="lower" />
       <user-name>root</user-name>
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index eedadc4..f6ecb62 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,18 +5,10 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="f008fe30-0711-42e2-bb33-17dcfdbad387" name="Changes" comment="pom">
+      <change afterPath="$PROJECT_DIR$/src/main/java/com/example/myproject/config/WebConfig.java" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/dataSources.local.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/dataSources.local.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/dataSources.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/dataSources.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/dataSources/6689f15a-5cd0-40b0-970c-713db3e7bac2.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/dataSources/6689f15a-5cd0-40b0-970c-713db3e7bac2.xml" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/src/main/java/com/example/myproject/controller/UserController.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/example/myproject/controller/UserController.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/src/main/java/com/example/myproject/repository/UserRepository.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/example/myproject/repository/UserRepository.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/src/main/java/com/example/myproject/service/UserService.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/example/myproject/service/UserService.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/src/main/resources/application.properties" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/resources/application.properties" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/src/test/java/com/example/myproject/controller/UserControllerTest.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/test/java/com/example/myproject/controller/UserControllerTest.java" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/target/classes/application.properties" beforeDir="false" afterPath="$PROJECT_DIR$/target/classes/application.properties" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/target/classes/com/example/myproject/controller/UserController.class" beforeDir="false" afterPath="$PROJECT_DIR$/target/classes/com/example/myproject/controller/UserController.class" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/target/classes/com/example/myproject/service/UserService.class" beforeDir="false" afterPath="$PROJECT_DIR$/target/classes/com/example/myproject/service/UserService.class" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/src/main/java/com/example/myproject/service/PostService.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/com/example/myproject/service/PostService.java" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -49,37 +41,39 @@
     <option name="hideEmptyMiddlePackages" value="true" />
     <option name="showLibraryContents" value="true" />
   </component>
-  <component name="PropertiesComponent">{
-  &quot;keyToString&quot;: {
-    &quot;JUnit.UserControllerTest.executor&quot;: &quot;Run&quot;,
-    &quot;JUnit.UserControllerTest.testUpdateUserAvatar.executor&quot;: &quot;Run&quot;,
-    &quot;RequestMappingsPanelOrder0&quot;: &quot;0&quot;,
-    &quot;RequestMappingsPanelOrder1&quot;: &quot;1&quot;,
-    &quot;RequestMappingsPanelWidth0&quot;: &quot;75&quot;,
-    &quot;RequestMappingsPanelWidth1&quot;: &quot;75&quot;,
-    &quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
-    &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
-    &quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
-    &quot;Spring Boot.MyProjectApplication.executor&quot;: &quot;Run&quot;,
-    &quot;git-widget-placeholder&quot;: &quot;my-branch&quot;,
-    &quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
-    &quot;last_opened_file_path&quot;: &quot;D:/大三/PT/pt.sql&quot;,
-    &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
-    &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
-    &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
-    &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
-    &quot;settings.editor.selected.configurable&quot;: &quot;project.propVCSSupport.DirectoryMappings&quot;,
-    &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;,
-    &quot;应用程序.MyProjectApplication.executor&quot;: &quot;Run&quot;
+  <component name="PropertiesComponent"><![CDATA[{
+  "keyToString": {
+    "JUnit.UserControllerTest.executor": "Run",
+    "JUnit.UserControllerTest.testUpdateUserAvatar.executor": "Run",
+    "JUnit.UserControllerTest.testUploadUserAvatar.executor": "Run",
+    "RequestMappingsPanelOrder0": "0",
+    "RequestMappingsPanelOrder1": "1",
+    "RequestMappingsPanelWidth0": "75",
+    "RequestMappingsPanelWidth1": "75",
+    "RunOnceActivity.OpenProjectViewOnStart": "true",
+    "RunOnceActivity.ShowReadmeOnStart": "true",
+    "RunOnceActivity.git.unshallow": "true",
+    "Spring Boot.MyProjectApplication.executor": "Run",
+    "git-widget-placeholder": "my-branch",
+    "kotlin-language-version-configured": "true",
+    "last_opened_file_path": "D:/PT/echo-backend/src/main/java/com/example/myproject/config",
+    "node.js.detected.package.eslint": "true",
+    "node.js.selected.package.eslint": "(autodetect)",
+    "node.js.selected.package.tslint": "(autodetect)",
+    "nodejs_package_manager_path": "npm",
+    "settings.editor.selected.configurable": "project.propVCSSupport.DirectoryMappings",
+    "vue.rearranger.settings.migration": "true",
+    "应用程序.MyProjectApplication.executor": "Run"
   },
-  &quot;keyToStringList&quot;: {
-    &quot;DatabaseDriversLRU&quot;: [
-      &quot;mysql_aurora&quot;
+  "keyToStringList": {
+    "DatabaseDriversLRU": [
+      "mysql_aurora"
     ]
   }
-}</component>
+}]]></component>
   <component name="RecentsManager">
     <key name="CopyFile.RECENT_KEYS">
+      <recent name="D:\PT\echo-backend\src\main\java\com\example\myproject\config" />
       <recent name="D:\PT\echo-backend\src\main\java\com\example\myproject\service" />
       <recent name="D:\PT\echo-backend\src\main\java\com\example\myproject\controller" />
     </key>
@@ -87,7 +81,7 @@
       <recent name="D:\study\学习资源\大三下\school\echo-backend\src\main\resources\mapper" />
     </key>
   </component>
-  <component name="RunManager" selected="JUnit.UserControllerTest.testUploadUserAvatar">
+  <component name="RunManager" selected="Spring Boot.MyProjectApplication">
     <configuration name="MyProjectApplication" type="Application" factoryName="Application" temporary="true">
       <option name="MAIN_CLASS_NAME" value="com.example.myproject.MyProjectApplication" />
       <module name="echo-backend" />
@@ -211,7 +205,8 @@
       <updated>1744348740342</updated>
       <workItem from="1749007243227" duration="1245000" />
       <workItem from="1749033374884" duration="7535000" />
-      <workItem from="1749048857906" duration="3104000" />
+      <workItem from="1749048857906" duration="4388000" />
+      <workItem from="1749109821491" duration="697000" />
     </task>
     <task id="LOCAL-00001" summary="pom">
       <option name="closed" value="true" />
@@ -262,4 +257,19 @@
     <MESSAGE value="pom" />
     <option name="LAST_COMMIT_MESSAGE" value="pom" />
   </component>
+  <component name="XDebuggerManager">
+    <breakpoint-manager>
+      <breakpoints>
+        <line-breakpoint enabled="true" type="java-method">
+          <url>file://$PROJECT_DIR$/src/test/java/com/example/myproject/controller/UserControllerTest.java</url>
+          <line>235</line>
+          <properties class="com.example.myproject.controller.UserControllerTest" method="testUploadUserAvatar">
+            <option name="EMULATED" value="true" />
+            <option name="WATCH_EXIT" value="false" />
+          </properties>
+          <option name="timeStamp" value="1" />
+        </line-breakpoint>
+      </breakpoints>
+    </breakpoint-manager>
+  </component>
 </project>
\ No newline at end of file
diff --git a/src/main/java/com/example/myproject/config/WebConfig.java b/src/main/java/com/example/myproject/config/WebConfig.java
new file mode 100644
index 0000000..5564452
--- /dev/null
+++ b/src/main/java/com/example/myproject/config/WebConfig.java
@@ -0,0 +1,15 @@
+package com.example.myproject.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+    @Override
+    public void addResourceHandlers(ResourceHandlerRegistry registry) {
+        // 访问 /uploads/** 映射到本地 D:/Desktop/echo/echo-backend/uploads/
+        registry.addResourceHandler("/uploads/**")
+                .addResourceLocations("file:D:/PT/echo-backend/uploads/");
+    }
+}
diff --git a/src/main/java/com/example/myproject/service/PostService.java b/src/main/java/com/example/myproject/service/PostService.java
index 90fc706..af032a5 100644
--- a/src/main/java/com/example/myproject/service/PostService.java
+++ b/src/main/java/com/example/myproject/service/PostService.java
@@ -1,5 +1,6 @@
 package com.example.myproject.service;
 
+import com.example.myproject.entity.Collections;
 import com.example.myproject.entity.Likes;
 import com.example.myproject.entity.Post;
 import com.example.myproject.entity.Users;
@@ -9,8 +10,8 @@
 import com.example.myproject.repository.UserRepository;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
-import com.example.myproject.entity.Collections;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -25,6 +26,7 @@
 
     @Autowired
     private UserRepository userRepository;
+
     @Autowired
     private LikesRepository likesRepository;
 
@@ -33,11 +35,10 @@
 
     private static final String IMAGE_DIR = "uploads/post/";
 
-
-    //创建帖子
+    // 创建帖子 - 添加 @Transactional
+    @Transactional
     public Map<String, Object> createPost(Long userId, String postContent, String title, MultipartFile[] imageFiles) {
-        // 查找用户信息
-        Users user = userRepository.findById(Long.valueOf(userId)).orElseThrow(() -> new RuntimeException("User not found"));
+        Users user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("User not found"));
         Post post = new Post();
         post.setUser_id(user.getUserId());
         post.setPostTime(new Date());
@@ -46,7 +47,6 @@
         post.setPostContent(postContent);
         post.setTitle(title);
 
-        // 处理多张图片的上传
         StringBuilder imageUrlsBuilder = new StringBuilder();
         if (imageFiles != null && imageFiles.length > 0) {
             for (int i = 0; i < imageFiles.length; i++) {
@@ -63,6 +63,7 @@
         }
         post.setImageUrl(imageUrlsBuilder.toString());
         Post savedPost = postRepository.save(post);
+
         Map<String, Object> response = new HashMap<>();
         response.put("postNo", savedPost.getPostNo());
         response.put("message", "帖子创建成功");
@@ -78,8 +79,8 @@
         return "/images/" + fileName;
     }
 
-
-    //编辑帖子
+    // 编辑帖子 - 添加 @Transactional
+    @Transactional
     public void updatePost(Long postId, Post post) {
         Post existingPost = postRepository.findById(postId).orElseThrow(() -> new RuntimeException("Post not found"));
         if (post.getTitle() != null) {
@@ -92,11 +93,11 @@
             existingPost.setImageUrl(post.getImageUrl());
         }
         existingPost.setPostTime(post.getPostTime());
-        // 保存更新后的帖子
         postRepository.save(existingPost);
     }
 
-    //删除帖子
+    // 删除帖子 - 添加 @Transactional
+    @Transactional
     public void deletePost(Long postId) {
         // 查找指定 ID 的帖子,如果不存在则抛出异常
         if (!postRepository.existsById(postId)) {
@@ -106,7 +107,8 @@
         postRepository.deleteById(postId);
     }
 
-    //点赞帖子(已完成)
+    // 点赞帖子 - 添加 @Transactional
+    @Transactional
     public void likePost(Long postId, Long userId) {
         // 查找指定 ID 的帖子
         Post post = postRepository.findById(postId).orElseThrow(() -> new RuntimeException("Post not found"));
@@ -121,7 +123,8 @@
         likesRepository.save(like);
     }
 
-    // 取消点赞帖子(已完成)
+    // 取消点赞帖子 - 已有 @Transactional
+    @Transactional
     public void unlikePost(Long postId, Long userId) {
         // 查找指定 ID 的帖子
         Post post = postRepository.findById(postId).orElseThrow(() -> new RuntimeException("Post not found"));
@@ -138,39 +141,78 @@
         postRepository.save(post);
     }
 
+//    // 获取帖子列表 - 不需要 @Transactional(只读操作)
+//    public Map<String, Object> getAllPosts() {
+//        List<Post> posts = postRepository.findAll();
+//        List<Map<String, Object>> postList = new ArrayList<>();
+//
+//        for (Post post : posts) {
+//            Map<String, Object> postMap = new LinkedHashMap<>();
+//            postMap.put("postNo", post.getPostNo());
+//            postMap.put("user_id", post.getUser_id());
+//            postMap.put("postContent", post.getPostContent());
+//            postMap.put("imgUrl", post.getImageUrl());
+//            postMap.put("title", post.getTitle());
+//            postMap.put("createdAt",
+//                    post.getPostTime() != null ? post.getPostTime().toString() : "未设置");
+//
+//            postMap.put("likeCount", post.getPostLikeNum());
+//            postMap.put("collectCount", post.getPostCollectNum());
+//
+//            postList.add(postMap);
+//        }
+//
+//        Map<String, Object> response = new HashMap<>();
+//        // 统计帖子数量
+//        response.put("total", postList.size());
+//        response.put("posts", postList);
+//
+//        return response;
+//    }
+public Map<String, Object> getAllPosts() {
+    List<Post> posts = postRepository.findAll();
+    List<Map<String, Object>> postList = new ArrayList<>();
 
-    // 获取帖子列表(已完成)
-    public Map<String, Object> getAllPosts() {
-        List<Post> posts = postRepository.findAll();
-        List<Map<String, Object>> postList = new ArrayList<>();
+    for (Post post : posts) {
+        Map<String, Object> postMap = new LinkedHashMap<>();
+        postMap.put("postNo", post.getPostNo());
+        postMap.put("user_id", post.getUser_id());
+        postMap.put("postContent", post.getPostContent());
+        postMap.put("imgUrl", post.getImageUrl());
+        postMap.put("title", post.getTitle());
+        postMap.put("createdAt",
+                post.getPostTime() != null ? post.getPostTime().toString() : "未设置");
 
-        for (Post post : posts) {
-            Map<String, Object> postMap = new LinkedHashMap<>();
-            postMap.put("postNo", post.getPostNo());
-            postMap.put("user_id", post.getUser_id());
-            postMap.put("postContent", post.getPostContent());
-            postMap.put("imgUrl", post.getImageUrl());
-            postMap.put("title", post.getTitle());
-            postMap.put("createdAt", post.getPostTime().toString());
-            postMap.put("likeCount", post.getPostLikeNum());
-            postMap.put("collectCount", post.getPostCollectNum());
+        postMap.put("likeCount", post.getPostLikeNum());
+        postMap.put("collectCount", post.getPostCollectNum());
 
-            postList.add(postMap);
+        // 查询用户信息
+        Optional<Users> userOptional = userRepository.findById(post.getUser_id());
+        if (userOptional.isPresent()) {
+            Users user = userOptional.get();
+            postMap.put("username", user.getUsername());
+            postMap.put("avatarUrl", user.getAvatarUrl());
+        } else {
+            postMap.put("username", "未知用户");
+            postMap.put("avatarUrl", null);
         }
 
-        Map<String, Object> response = new HashMap<>();
-        // 统计帖子数量
-        response.put("total", postList.size());
-        response.put("posts", postList);
-
-        return response;
+        postList.add(postMap);
     }
 
+    Map<String, Object> response = new HashMap<>();
+    // 统计帖子数量
+    response.put("total", postList.size());
+    response.put("posts", postList);
+
+    return response;
+}
+
+
+    // 获取单个帖子 - 不需要 @Transactional(只读操作)
     public Map<String, Object> getPostById(Long postId) {
-        // 获取帖子
         Optional<Post> postOptional = postRepository.findById(postId);
 
-        // 如果帖子存在
         if (postOptional.isPresent()) {
             Post post = postOptional.get();
             Map<String, Object> postData = new LinkedHashMap<>();
@@ -181,14 +223,14 @@
 
             if (user != null) {
                 postData.put("username", user.getUsername());
-                postData.put("avatar_url", user.getAvatarUrl());
+                postData.put("avatarUrl", user.getAvatarUrl());  // 改成 avatarUrl,保持驼峰
             } else {
-                postData.put("username", null);
-                postData.put("avatar_url", null);
+                postData.put("username", "未知用户");
+                postData.put("avatarUrl", null);
             }
 
             postData.put("postContent", post.getPostContent());
-            postData.put("imageUrl", post.getImageUrl());
+            postData.put("imgUrl", post.getImageUrl());  // 改成 imgUrl,和列表接口保持一致
             postData.put("postTime", post.getPostTime());
             postData.put("postLikeNum", post.getPostLikeNum());
             postData.put("postCollectNum", post.getPostCollectNum());
@@ -201,7 +243,8 @@
     }
 
 
-    //收藏
+    // 收藏帖子 - 添加 @Transactional
+    @Transactional
     public void collectPost(Long postId, Long userId) {
         Post post = postRepository.findById(postId).orElseThrow(() -> new RuntimeException("Post not found"));
         post.setPostCollectNum(post.getPostCollectNum() + 1);
@@ -214,7 +257,8 @@
         collectionsRepository.save(collection);
     }
 
-    //取消收藏
+    // 取消收藏 - 添加 @Transactional
+    @Transactional
     public void uncollectPost(Long postId, Long userId) {
         Post post = postRepository.findById(postId).orElseThrow(() -> new RuntimeException("Post not found"));
         // 减少帖子收藏数
@@ -226,8 +270,6 @@
         // 从收藏表中删除对应记录
         collectionsRepository.deleteLikeByUserIdAndPostNo(userId, postId);
     }
-
-
     // 获取用户收藏的所有帖子
     public List<Map<String, Object>> getAllCollections(Long userId) {
         // 获取用户收藏的帖子ID
@@ -266,6 +308,4 @@
         }
         return response;
     }
-
-
-}
+}
\ No newline at end of file
diff --git a/target/classes/com/example/myproject/config/WebConfig.class b/target/classes/com/example/myproject/config/WebConfig.class
new file mode 100644
index 0000000..7e6fb72
--- /dev/null
+++ b/target/classes/com/example/myproject/config/WebConfig.class
Binary files differ
diff --git a/target/classes/com/example/myproject/service/PostService.class b/target/classes/com/example/myproject/service/PostService.class
index 87e157b..c29d9a1 100644
--- a/target/classes/com/example/myproject/service/PostService.class
+++ b/target/classes/com/example/myproject/service/PostService.class
Binary files differ