图片上传成功却无法显示:静态资源路径配置问题解析

图片上传成功却无法显示:静态资源路径配置问题解析

1、故事的背景

最近,有个学弟做了一个简单的后台管理页面。于是他开始巴拉巴拉撘框架,写代码,一顿操作猛如虎,终于将一个简单的壳子搭建完毕。但是在实现功能:点击头像弹出上传图片进行头像替换的时候,卡壳了~

原来啊,他发现图片上传成功并且图片的信息都保存进数据库后,页面没有加载出图片,这可就给他犯了难,捣鼓了半天,还是没有搞定。

2、问题剖析

于是他就过来向我求助,让我帮他一起来研究代码,看看是哪个步骤出了问题。这里,我将简单的贴出关键的代码信息。

2.1 前端代码的剖析

前端主要是实现了一个用户信息编辑页面,主功能包括用户信息展示和编辑,以及头像上传和显示。我们来逐步分解并详细解释前端代码:

首先看模板部分,使用了Element UI的表单组件``,绑定user数据模型。使用``组件实现头像上传功能,`action`属性定义上传地址,`accept`属性限制上传文件类型为图片,`show-file-list`设置为false用来隐藏文件列表。接着看`

实际上,这里不知道是代码才写到一半还是没给到我完整代码的原因。单从这部分代码看,功能也并不完善,达不到上传图片并展示图片的预期,但是点击上传后图片是没有任何变化的。所以我以这段代码为基础,进行了完善,来看看页面是否可以正常上传显示。

改善后的代码:

与一开始的代码相比:

添加了 beforeUpload 方法,用于在上传文件之前进行校验,如果文件不是图片类型,我们直接显示错误信息并阻止继续上传。添加了 handleSuccess 方法,用于处理上传成功后的逻辑,如果上传成功,会显示成功信息,并重新调用getUser 方法以获取最新的头像地址。添加了 handleError 方法,用于处理上传失败后的逻辑。如果上传失败,会显示错误信息。添加了 handleFileChange 方法,用于在文件选择变化时更新显示的图片。通过 URL.createObjectURL 方法生成临时的 URL 来显示选择的图片。

通过我们打印的日志可以看到,图片已经上传成功,且数据也已经入库,但是页面上的图片还是没有显示成功。

那么在确定前端已经没有问题了后,接下来我们就需要排查后端,看是什么原因导致的。

2.2 后端代码的剖析

后端主要是提供文件上传的接口,将个人信息(头像图片地址,用户名,性别,年龄等)进行编辑更新,同时还提供了用户信息查询接口,用来查询个人信息。我们来逐步分解并详细解释后端代码:

@CrossOrigin(origins = "http://localhost:8080")

@RestController

@RequestMapping("/upload")

public class Upload {

@Autowired

private UploadService uploadService;

/**

* 头像上传

*/

@PostMapping("/avatar")

public RestResult avatar(@RequestBody @RequestParam("file") MultipartFile file, HttpServletRequest request) throws Exception {

if (!file.isEmpty()) {

Boolean b = uploadService.avatarUpload(file, request);

if (Boolean.TRUE.equals(b)) {

return RestResult.build(true);

}

}

throw new Exception("头像上传失败");

}

}

这段代码的主要功能是处理头像上传的 HTTP POST 请求。它通过 UploadService 服务来处理文件上传逻辑,并返回上传结果。如果上传成功,这个控制器类还简单配置了跨域支持,允许来自 http://localhost:8080 的请求。

我们直接来看看具体实现的逻辑,逻辑很简单,就是从配置文件中获取头像上传的默认路径,处理上传文件信息并将上传的文件保存到指定路径。生成文件的访问URL,并调用 userService.updateAvatar 方法更新用户头像URL到数据库。看着也没啥问题。

@Service

public class UploadServiceImpo implements UploadService {

@Autowired

private UserService userService;

//头像上传路径

@Value("${weibo.profile}")

private String defaultBaseDir;

@Override

public Boolean avatarUpload(MultipartFile file, HttpServletRequest request) {

//获取当前头像上传路径

String avatar = defaultBaseDir;

//获取当前用户id并且修改用户的头像地址

// 文件名称 用户id

// 获取文件的名称

String originalFilename = file.getOriginalFilename();

// 文件后缀 例如:.png

assert originalFilename != null;

String fileSuffix = originalFilename.substring(originalFilename.lastIndexOf("."));

// uuid 生成文件名

String uuid = String.valueOf(UUID.randomUUID());

// 根路径,

String basePath = avatar + uuid;

// 新的文件名,使用uuid生成文件名

String fileName = uuid + fileSuffix;

// 创建新的文件

File fileExist = new File(basePath);

// 文件夹不存在,则新建

if (!fileExist.exists()) {

fileExist.mkdirs();

}

// 获取文件对象

File newfile = new File(basePath, fileName);

try {

// 完成文件的上传

file.transferTo(newfile);

} catch (Exception e) {

throw new RuntimeException("文件上传失败");

}

//判断文件是否上传成功并保存到数据库

String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/image/" + uuid + "/" + fileName;

return userService.updateAvatar(123L, url);

}

}

接着我们来确认下配置文件,图片的存储路径也没啥问题。

server:

port: 8081

weibo:

# 文件路径

profile: G:/working-idea/vue3/vue3/src/assets/images/

2.3 问题剖析

现状

前端上传图片的功能已经成功上传图片并保存到数据库,但页面上的图片仍然无法显示。将后端保存的图片地址在尝试浏览器打开,可以发现访问不到。

原因分析

1. 路径问题,前端请求的图片路径可能有误。如果使用的是相对路径,路径相对于前端页面的位置可能不正确。后端生成的图片URL可能不正确,如URL中拼写错误或存在多余的空格。

2. 服务器配置问题,服务器可能没有配置正确的静态资源映射。例如,在Spring Boot中,需要配置静态资源路径,确保图片可以被正确访问。

3. 浏览器缓存问题,有时候浏览器会缓存图片,导致显示的是旧的图片。尝试清除浏览器缓存或使用无痕模式查看图片是否能正常显示。

4. 权限问题,上传的图片文件没有正确的读取权限,导致Web服务器可能没有权限读取这些文件。

5. 前端代码问题,前端代码中使用的图片URL可能不正确,如没有拼写错误或路径错误。前端代码未正确加载了图片,例如使用``标签或通过JavaScript动态加载图片。

6. 图片格式问题,上传的图片格式可能不被浏览器支持。某些浏览器可能不支持某些图片格式。

基于上面的代码剖析,可以看出项目比较简单,也没有做权限控制,代码也验证过了,有问题我们也已经进行了优化,上传的图片格式也是jpeg,是浏览器支持的格式之一。

实际上,遇到这种问题,在确定前后端代码都没有问题但是图片又显示不出来的情况下,一般直接查看是否配置了正确的静态资源映射。 于是我仔细查看了后端代码,果然!没有发现到有配置静态资源路径,那么问题就很明朗了,在确保路径正确的情况下,由于后端没有加载静态资源,所以图片是无法被正确访问的。

找到问题点就好办了,我们先加上静态资源处理器,让所有以 `/image/` 开头的请求都会被映射到指定的文件系统路径。

@Configuration

public class WebMvcConfig implements WebMvcConfigurer {

@Value("${default.url}")

private String defaultUrl;

@Override

public void addResourceHandlers(ResourceHandlerRegistry resourceHandlerRegistry) {

resourceHandlerRegistry.addResourceHandler("/image/**")

.addResourceLocations("file:" + defaultUrl);

}

}

可以发现,现在是已经可以正常显示了,且进行图片上传时,也能够正常上传成功并更新显示的图片。

3. 复盘:如何排查问题并找到原因点

实际在开发过程中,我们总会遇到大大小小的各种问题,而遇到问题时,如何快速有效地排查问题并找到原因点是每个开发者所必备的技能。就拿这一次学弟遇到的问题,下面是我们在解决头像上传后页面无法显示图片问题时的复盘,希望能为大家提供一些参考和启示。

3.1. 确认问题现象

首先,我们需要明确问题的具体现象。在这个案例中,问题现象是:图片上传成功并保存到数据库后,页面上的图片无法显示。

3.2. 逐步排查

3.2.1 前端代码排查

检查前端代码:确认前端代码中图片URL的获取和显示逻辑是否正确。我们检查了 组件和 标签的 src 属性,确保它们正确地绑定了图片URL。调试前端代码:通过浏览器开发者工具查看网络请求和控制台输出,确认图片URL是否正确生成,并且没有404或其他错误。3.2.2 后端代码排查

检查后端代码:确认后端代码中图片上传和URL生成的逻辑是否正确。我们检查了 UploadService 中的 avatarUpload 方法,确保图片正确上传并生成正确的URL。调试后端代码:通过日志输出和断点调试,确认图片上传和URL生成的过程中没有异常或错误。3.2.3 配置文件排查

检查配置文件:确认配置文件中图片存储路径是否正确。我们检查了 application.yml 中的 weibo.profile 配置项,确保路径正确无误。3.3. 分析可能原因

在排查过程中,我们列出了可能导致问题的原因:

路径问题:图片URL路径可能不正确。服务器配置问题:服务器可能没有正确配置静态资源映射。浏览器缓存问题:浏览器可能缓存了旧的图片。权限问题:上传的图片可能没有正确的读取权限。前端代码问题:前端代码中可能存在拼写错误或路径错误。图片格式问题:上传的图片格式可能不被浏览器支持。3.4. 逐一验证

我们逐一验证了上述可能原因,最终发现是由于服务器没有配置静态资源映射,导致图片无法被正确访问。

3.5. 解决问题

在确认问题原因后,我们通过添加静态资源处理器解决了问题。

4. 总结

通过这次排查问题的过程,我们不仅解决了学弟的问题,还深入探讨了前后端代码的实现和可能遇到的问题。可以总结出以下经验:

- **明确问题现象**:首先明确问题的具体现象,有助于缩小排查范围。

- **逐步排查**:从前端到后端,从代码到配置文件,逐步排查,确保每个环节都没有问题。

- **列出可能原因**:列出所有可能导致问题的原因,逐一验证。

- **确认问题原因**:通过验证,确认问题的根本原因。

- **解决问题**:针对问题原因,采取相应的解决措施。

希望这些经验能帮助大家在未来的开发过程中,更快更有效地排查问题并找到原因点。

相关推荐