diff --git a/src/main/java/com/webgame/webgamebackend/common/config/StaticResourceConfig.java b/src/main/java/com/webgame/webgamebackend/common/config/StaticResourceConfig.java index 158a612..03e1361 100644 --- a/src/main/java/com/webgame/webgamebackend/common/config/StaticResourceConfig.java +++ b/src/main/java/com/webgame/webgamebackend/common/config/StaticResourceConfig.java @@ -8,18 +8,25 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; * 静态资源配置 * * 将本地 uploads/ 目录映射为 /uploads/** URL,用于头像等用户上传文件的访问。 + * 使用绝对路径避免 Tomcat 临时工作目录导致的路径不一致问题。 */ @Configuration public class StaticResourceConfig implements WebMvcConfigurer { + /** 上传文件根目录(相对于项目工作目录) */ + private static final String UPLOAD_DIR = "uploads/"; + /** * 注册静态资源处理器 * - * /uploads/avatars/xxx.jpg → file:./uploads/avatars/xxx.jpg + * /uploads/avatars/xxx.jpg → file:/uploads/avatars/xxx.jpg */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { + // 使用正斜杠替换反斜杠,确保 Windows 下 file: URL 格式正确 + String userDir = System.getProperty("user.dir").replace("\\", "/"); + String absoluteUploadPath = "file:" + userDir + "/" + UPLOAD_DIR; registry.addResourceHandler("/uploads/**") - .addResourceLocations("file:./uploads/"); + .addResourceLocations(absoluteUploadPath); } } diff --git a/src/main/java/com/webgame/webgamebackend/service/impl/UserServiceImpl.java b/src/main/java/com/webgame/webgamebackend/service/impl/UserServiceImpl.java index 96c7583..14c95d3 100644 --- a/src/main/java/com/webgame/webgamebackend/service/impl/UserServiceImpl.java +++ b/src/main/java/com/webgame/webgamebackend/service/impl/UserServiceImpl.java @@ -31,6 +31,15 @@ public class UserServiceImpl implements UserService { /** 头像存储目录(相对于项目工作目录) */ private static final String AVATAR_DIR = "uploads/avatars"; + + /** + * 获取头像存储的绝对路径目录 + * + * 使用 user.dir 构建绝对路径,避免 Tomcat 临时工作目录导致 FileNotFoundException。 + */ + private Path getAvatarDir() { + return Paths.get(System.getProperty("user.dir"), AVATAR_DIR).toAbsolutePath(); + } /** 允许的头像文件类型 */ private static final Set ALLOWED_CONTENT_TYPES = Set.of( "image/jpeg", "image/png", "image/webp", "image/gif" @@ -109,8 +118,8 @@ public class UserServiceImpl implements UserService { .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)); try { - // 确保目录存在 - Path avatarDir = Paths.get(AVATAR_DIR); + // 确保目录存在(使用绝对路径,避免 Tomcat 临时目录问题) + Path avatarDir = getAvatarDir(); Files.createDirectories(avatarDir); // 删除旧头像文件(如果存在且不是默认 SVG) @@ -163,7 +172,9 @@ public class UserServiceImpl implements UserService { return; } try { - Path oldFile = Paths.get(avatarPath.substring(1)); // 去掉开头的 / + // 从 URL 路径中提取文件名,使用绝对路径删除 + String filename = avatarPath.substring(avatarPath.lastIndexOf('/') + 1); + Path oldFile = getAvatarDir().resolve(filename); Files.deleteIfExists(oldFile); log.debug("[用户服务] 旧头像已删除: {}", oldFile); } catch (IOException e) { diff --git a/uploads/avatars/729bf910-6ca8-43a5-b7d7-5ebecf4db810.jpg b/uploads/avatars/729bf910-6ca8-43a5-b7d7-5ebecf4db810.jpg new file mode 100644 index 0000000..791c3be Binary files /dev/null and b/uploads/avatars/729bf910-6ca8-43a5-b7d7-5ebecf4db810.jpg differ