山东大学软件学院项目实训-基于大模型的模拟面试系统-专栏管理部分
本周我的主要任务是关于专栏管理部分的完善。
专栏图片的显示问题
问题分析
根据代码可知:图片URL来自于portfolio.headImgUrl
,而且如果URL不存在的话,应该显示的是无图片,而网页中显示加载失败说明portfolio.headImgUrl
应该是存在的,但是路径可能有问题。在控制台中的404报错也印证了这一点。
对其中的URL进行解码可以得到http://localhost:3000/portfolio/上传失败!
,看来是图片在上传时就有问题,导致URL被拼接成了上传失败。
在后端进行DeBug调试时找到问题所在,原来是配置文件中的存储图片的目录的路径有问题,导致返回了一个上传失败。
问题解决
通过修改配置文件中的路径使其能够显示正常的路径而不是上传失败,但现在路径仍不是我们想要的路径,所以还需要将存到数据库中的图片路径逻辑进行修改。
现在图片已经能够正确存储在后端的static文件夹下,并且其URL正确的存储到了数据库中。
后端
然后需要找到前端向后端请求的函数:
fetchPostDetail({ commit }, params = {}) {
// const delay = fetchDelay(
// isBrowser
// )
// if (isBrowser) {
// Vue.nextTick(() => {
// window.scrollTo(0, 300);
// })
// }
if (typeof params.portfolio_id === 'undefined') {
commit('updateDetailData', getDefaultListData())
return;
}
commit('updateDetailFetching', true)
// commit('updateDetailData', {})
return this.$axios
.$get(`${PORTFOLIO_API_PATH}/detail/${params.portfolio_id}`)
.then(response => {
return new Promise(resolve => {
commit('updateDetailData', response)
commit('updateDetailFetching', false)
resolve(response)
// delay(() => {
// resolve(response)
// })
})
})
.catch(error => {
commit('updateDetailFetching', false)
return Promise.reject(error)
})
}
上述函数通过调用后端接口(${PORTFOLIO_API_PATH}/detail/${params.portfolio_id})
获取作品集详情数据,更新到 Vuex store 的detail.data
中,而作品集封面的URL就在detail.data
中。
添加前端请求图片的接口并以base64编码的形式返回。
@GetMapping("/image/{idPortfolio}/base64")
public GlobalResult<String> getPortfolioImageAsBase64(@PathVariable Long idPortfolio, @RequestParam(defaultValue = "0") Integer type) throws IOException {
// Get the portfolio DTO which contains the image path
PortfolioDTO portfolioDTO = portfolioService.findPortfolioDTOById(idPortfolio, type);
if (portfolioDTO == null || portfolioDTO.getHeadImgUrl() == null) {
throw new FileNotFoundException("Portfolio or image not found");
}
String path = portfolioDTO.getHeadImgUrl().replace("src/main/resources/", "");
String extension = path.substring(path.lastIndexOf(".") + 1);
// 3. 确定MIME类型
String mimeType;
switch (extension) {
case "png": mimeType = "image/png"; break;
case "jpg":
case "jpeg": mimeType = "image/jpeg"; break;
case "gif": mimeType = "image/gif"; break;
case "svg": mimeType = "image/svg+xml"; break;
case "webp": mimeType = "image/webp"; break;
default: mimeType = "application/octet-stream";
}
ClassPathResource resource = new ClassPathResource(path);
// Read file content and encode as base64
try (InputStream inputStream = resource.getInputStream()) {
byte[] fileContent = IOUtils.toByteArray(inputStream);
String base64 = Base64.getEncoder().encodeToString(fileContent);
String res = "data:" + mimeType + ";base64," + base64;
GlobalResult<String> result = GlobalResultGenerator.genSuccessResult("success");
result.setData(res);
return result;
} catch (IOException e) {
throw new RuntimeException("加载图片失败: " + path, e);
}
}
前端
添加该函数单独获取base64编码的图片。
async fetchImageAsBase64() {
if(this.portfolio?.headImgUrl?.startsWith('data:image')){
return;
}
try {
if (!this.portfolio?.headImgUrl) return;
if (this.portfolio.headImgUrl.startsWith('data:image')) {
return this.portfolio.headImgUrl;
}
const response = await this.$axios.$get(
`/api/portfolio/image/${this.portfolio.idPortfolio}/base64`,
{ responseType: 'text' }
);
this.imgUrl = response;
console.log(this.imgUrl)
} catch (error) {
console.error('获取Base64图片失败:', error);
return null; // 或返回占位图URL
}
}
},