springboot+vue,上传图片,回显,以及报错404的问题

最近遇到一个问题,上传图片到服务器以后,回显不了,报错404;

历时三天终于找到解决办法:

1.后端代码:

@RestController
@RequestMapping("file")
@SuppressWarnings({"unchecked","rawtypes"})
public class FileController{@Autowiredprivate ConfigService configService;/*** 上传文件*/@RequestMapping("/upload")public R upload(@RequestParam("file") MultipartFile file,String type) throws Exception {if (file.isEmpty()) {throw new EIException("上传文件不能为空");}String fileExt = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")+1);
//		File path = new File(ResourceUtils.getURL("classpath:static").getPath());
//		if(!path.exists()) {
//		    path = new File("");
//		}
//		File upload = new File(ResourceUtils.getURL("classpath:static").getPath()+"\\upload");
//		if(!upload.exists()) {
//		    upload.mkdirs();
//		}String fileName = new Date().getTime()+"."+fileExt;
//这里写自己上传的路径File dest = new File("D:\\Edge\\537\\daima\\springboot60zv5\\src\\main\\resources\\static\\upload"+"\\"+fileName);file.transferTo(dest);if(StringUtils.isNotBlank(type) && type.equals("1")) {ConfigEntity configEntity = configService.selectOne(new EntityWrapper<ConfigEntity>().eq("name", "faceFile"));if(configEntity==null) {configEntity = new ConfigEntity();configEntity.setName("faceFile");configEntity.setValue(fileName);} else {configEntity.setValue(fileName);}configService.insertOrUpdate(configEntity);}return R.ok().put("file", fileName);}@IgnoreAuth@RequestMapping("/download")public ResponseEntity<byte[]> download(@RequestParam String fileName) {try {File path = new File(ResourceUtils.getURL("classpath:static").getPath());if(!path.exists()) {path = new File("");}File upload = new File(path.getAbsolutePath(),"/upload/");if(!upload.exists()) {upload.mkdirs();}File file = new File(upload.getAbsolutePath()+"/"+fileName);if(file.exists()){/*if(!fileService.canRead(file, SessionManager.getSessionUser())){getResponse().sendError(403);}*/HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);headers.setContentDispositionFormData("attachment", fileName);return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers, HttpStatus.CREATED);}} catch (IOException e) {e.printStackTrace();}return new ResponseEntity<byte[]>(HttpStatus.INTERNAL_SERVER_ERROR);}}

2.前端代码:

<el-form-item class="upload" v-if="type!='info' && !ro.touxiang" label="头像" prop="touxiang"><file-uploadtip="点击上传头像"action="file/upload":limit="3":multiple="true":fileUrls="ruleForm.touxiang?ruleForm.touxiang:''"@change="touxiangUploadChange"></file-upload></el-form-item>
<template><div><!-- 上传文件组件 --><el-uploadref="upload":action="getActionUrl"list-type="picture-card":multiple="multiple":limit="limit":headers="myHeaders":file-list="fileList":on-exceed="handleExceed":on-preview="handleUploadPreview":on-remove="handleRemove":on-success="handleUploadSuccess":on-error="handleUploadErr":before-upload="handleBeforeUpload"><i class="el-icon-plus"></i><div slot="tip" class="el-upload__tip" style="color:#838fa1;">{{tip}}</div></el-upload><el-dialog :visible.sync="dialogVisible" size="tiny" append-to-body><img width="100%" :src="dialogImageUrl" alt></el-dialog></div>
</template>
<script>
import storage from "@/utils/storage";
import base from "@/utils/base";
export default {data() {return {// 查看大图dialogVisible: false,// 查看大图dialogImageUrl: "",// 组件渲染图片的数组字段,有特殊格式要求fileList: [],fileUrlList: [],myHeaders:{}};},props: ["tip", "action", "limit", "multiple", "fileUrls"],mounted() {this.init();this.myHeaders= {'Token':storage.get("Token")}},watch: {fileUrls: function(val, oldVal) {//   console.log("new: %s, old: %s", val, oldVal);this.init();}},computed: {// 计算属性的 gettergetActionUrl: function() {// return base.url + this.action + "?token=" + storage.get("token");return `/${this.$base.name}/` + this.action;}},methods: {// 初始化init() {//   console.log(this.fileUrls);if (this.fileUrls) {this.fileUrlList = this.fileUrls.split(",");let fileArray = [];this.fileUrlList.forEach(function(item, index) {var url = item;var name = index;var file = {name: name,url: url};fileArray.push(file);});this.setFileList(fileArray);}},handleBeforeUpload(file) {},// 上传文件成功后执行handleUploadSuccess(res, file, fileList) {if (res && res.code === 0) {fileList[fileList.length - 1]["url"] =this.$base.url + "upload/" + file.response.file;this.setFileList(fileList);this.$emit("change", this.fileUrlList.join(","));} else {this.$message.error(res.msg);}},// 图片上传失败handleUploadErr(err, file, fileList) {this.$message.error("文件上传失败");},// 移除图片handleRemove(file, fileList) {this.setFileList(fileList);this.$emit("change", this.fileUrlList.join(","));},// 查看大图handleUploadPreview(file) {this.dialogImageUrl = file.url;this.dialogVisible = true;},// 限制图片数量handleExceed(files, fileList) {this.$message.warning(`最多上传${this.limit}张图片`);},// 重新对fileList进行赋值setFileList(fileList) {var fileArray = [];var fileUrlArray = [];// 有些图片不是公开的,所以需要携带token信息做权限校验var token = storage.get("token");fileList.forEach(function(item, index) {var url = item.url.split("?")[0];var name = item.name;var file = {name: name,url: url + "?token=" + token};fileArray.push(file);fileUrlArray.push(url);});this.fileList = fileArray;this.fileUrlList = fileUrlArray;}}
};
</script>
<style lang="scss" scoped>
</style>
<template><div><!-- 图片上传组件辅助--><el-uploadclass="avatar-uploader":action="getActionUrl"name="file":headers="header":show-file-list="false":on-success="uploadSuccess":on-error="uploadError":before-upload="beforeUpload"></el-upload><quill-editorclass="editor"v-model="value"ref="myQuillEditor":options="editorOption"@blur="onEditorBlur($event)"@focus="onEditorFocus($event)"@change="onEditorChange($event)"></quill-editor></div>
</template>
<script>
// 工具栏配置
const toolbarOptions = [["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线["blockquote", "code-block"], // 引用  代码块[{ header: 1 }, { header: 2 }], // 1、2 级标题[{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表[{ script: "sub" }, { script: "super" }], // 上标/下标[{ indent: "-1" }, { indent: "+1" }], // 缩进// [{'direction': 'rtl'}],                         // 文本方向[{ size: ["small", false, "large", "huge"] }], // 字体大小[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色[{ font: [] }], // 字体种类[{ align: [] }], // 对齐方式["clean"], // 清除文本格式["link", "image", "video"] // 链接、图片、视频
];import { quillEditor } from "vue-quill-editor";
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";export default {props: {/*编辑器的内容*/value: {type: String},action: {type: String},/*图片大小*/maxSize: {type: Number,default: 4000 //kb}},components: {quillEditor},data() {return {content: this.value,quillUpdateImg: false, // 根据图片上传状态来确定是否显示loading动画,刚开始是false,不显示editorOption: {placeholder: "",theme: "snow", // or 'bubble'modules: {toolbar: {container: toolbarOptions,// container: "#toolbar",handlers: {image: function(value) {if (value) {// 触发input框选择图片文件document.querySelector(".avatar-uploader input").click();} else {this.quill.format("image", false);}}// link: function(value) {//   if (value) {//     var href = prompt('请输入url');//     this.quill.format("link", href);//   } else {//     this.quill.format("link", false);//   }// },}}}},// serverUrl: `${base.url}sys/storage/uploadSwiper?token=${storage.get('token')}`, // 这里写你要上传的图片服务器地址header: {// token: sessionStorage.token'Token': this.$storage.get("Token")} // 有的图片服务器要求请求头需要有token};},computed: {// 计算属性的 gettergetActionUrl: function() {// return this.$base.url + this.action + "?token=" + this.$storage.get("token");return `/${this.$base.name}/` + this.action;}},methods: {onEditorBlur() {//失去焦点事件},onEditorFocus() {//获得焦点事件},onEditorChange() {console.log(this.value);//内容改变事件this.$emit("input", this.value);},// 富文本图片上传前beforeUpload() {// 显示loading动画this.quillUpdateImg = true;},uploadSuccess(res, file) {// res为图片服务器返回的数据// 获取富文本组件实例let quill = this.$refs.myQuillEditor.quill;// 如果上传成功if (res.code === 0) {// 获取光标所在位置let length = quill.getSelection().index;// 插入图片  res.url为服务器返回的图片地址quill.insertEmbed(length, "image", this.$base.url+ "upload/" +res.file);// 调整光标到最后quill.setSelection(length + 1);} else {this.$message.error("图片插入失败");}// loading动画消失this.quillUpdateImg = false;},// 富文本图片上传失败uploadError() {// loading动画消失this.quillUpdateImg = false;this.$message.error("图片插入失败");}}
};
</script> <style>
.editor {line-height: normal !important;height: 400px;
}
.ql-snow .ql-tooltip[data-mode="link"]::before {content: "请输入链接地址:";
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {border-right: 0px;content: "保存";padding-right: 0px;
}.ql-snow .ql-tooltip[data-mode="video"]::before {content: "请输入视频地址:";
}.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {content: "14px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {content: "10px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {content: "18px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {content: "32px";
}.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {content: "文本";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {content: "标题1";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {content: "标题2";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {content: "标题3";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {content: "标题4";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {content: "标题5";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {content: "标题6";
}.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {content: "标准字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {content: "衬线字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {content: "等宽字体";
}
</style>

3.解决404问题的关键:
 

package com.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;import com.interceptor.AuthorizationInterceptor;@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport{@Beanpublic AuthorizationInterceptor getAuthorizationInterceptor() {return new AuthorizationInterceptor();}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(getAuthorizationInterceptor()).addPathPatterns("/**").excludePathPatterns("/static/**");super.addInterceptors(registry);}/*** springboot 2.0配置WebMvcConfigurationSupport之后,会导致默认配置被覆盖,要访问静态资源需要重写addResourceHandlers方法*/@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {/*	registry.addResourceHandler("/**").addResourceLocations("classpath:/resources/").addResourceLocations("classpath:/static/").addResourceLocations("classpath:/admin/").addResourceLocations("classpath:/front/").addResourceLocations("classpath:/public/");super.addResourceHandlers(registry);*/registry.addResourceHandler("/**").addResourceLocations("classpath:/resources/").addResourceLocations("classpath:/static/").addResourceLocations("classpath:/upload/").addResourceLocations("classpath:/admin/").addResourceLocations("classpath:/front/").addResourceLocations("classpath:/public/");registry.addResourceHandler("/upload/**").addResourceLocations("file:D:\\Edge\\537\\daima\\springboot60zv5\\src\\main\\resources\\static\\upload\\");super.addResourceHandlers(registry);}
}

需要再config中写下这段代码;

  • registry.addResourceHandler("/upload/**"):这行代码使用了registry对象(可能是ResourceHandlerRegistry或类似的注册表),向其中添加一个资源处理器。

  • "/upload/**":这是一个路径模式,表示要匹配的资源路径。/**表示匹配任意子路径,所以/upload/及其子路径下的资源都会被这个处理器处理。

  • .addResourceLocations("file:D:\\Edge\\537\\daima\\springboot60zv5\\src\\main\\resources\\static\\upload\\"):这行代码指定了资源的位置。在这个例子中,资源位于本地文件系统的指定路径中。

综合起来,这段代码的作用是将所有对/upload/及其子路径的请求都路由到本地文件系统的指定路径中。这样,当发送/upload/或其下的请求时,服务器将会返回该路径下的文件。

		registry.addResourceHandler("/upload/**").addResourceLocations("file:D:\\Edge\\537\\daima\\springboot60zv5\\src\\main\\resources\\static\\upload\\");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/732747.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面试经典150题【61-70】

文章目录 面试经典150题【61-70】61.旋转链表86.分隔链表104. 二叉树的最大深度100.相同的树226.翻转二叉树101.对称二叉树105.从前序与中序遍历序列构造二叉树106.从后序和中序遍历序列构造二叉树117.填充每个节点的下一个右侧节点指针II114.二叉树展开为链表 面试经典150题【…

留学|谈PS|耶鲁大学管理学院招生办执行主任谈个人PS

仅仅为了共同学习与分享 内容提要:在一篇个人自述中&#xff0c;我们要求申请人将他们的过去和未来有机地结合起来。我们把这种自传叫作“职业目标”自传。它为我们提供了确凿的信息&#xff0c;同时也可以确定申请人是否具有对自己及其职业的综合性反思能力。通常的情况是&am…

PostgreSQL 流复制

文章目录 1.流复制介绍2.异步流复制2.1.主库部署2.2.备库部署2.3.测试 3.同步复制3.1.主库部署3.2.备库部署3.3.测试 4.主备切换 开源中间件 # PostgreSQLhttps://iothub.org.cn/docs/middleware/ https://iothub.org.cn/docs/middleware/postgresql/postgres-stream/1.流复制…

Linux运维_Bash脚本_编译安装Mesa-23.3.6(OpenGL)

Linux运维_Bash脚本_编译安装Mesa-23.3.6(OpenGL) Bash (Bourne Again Shell) 是一个解释器&#xff0c;负责处理 Unix 系统命令行上的命令。它是由 Brian Fox 编写的免费软件&#xff0c;并于 1989 年发布的免费软件&#xff0c;作为 Sh (Bourne Shell) 的替代品。 您可以在…

为什么main方法在Java中代表主线程?

main 方法在 Java 等编程语言中确实代表着程序的入口点&#xff0c;也就是程序开始执行的地方。当我们启动一个 Java 应用程序时&#xff0c;JVM&#xff08;Java 虚拟机&#xff09;会首先查找 main 方法&#xff0c;并从那里开始执行程序。 关于为什么 main 方法代表主线程&a…

unity学习(53)——选择角色界面--分配服务器返回的信息

好久没写客户端了&#xff0c;一上手还不太适应 1.经过测试&#xff0c;成功登陆后&#xff0c;客户端请求list_request&#xff0c;成功返回&#xff0c;如下图&#xff1a; 可见此时model第三个位置的参数是1.也成功返回了所有已注册角色的信息。 2.之前已知创建的角色信息…

141 Linux 系统编程18 ,线程,线程实现原理,ps –Lf 进程 查看

一 线程概念 什么是线程 LWP&#xff1a;light weight process 轻量级的进程&#xff0c;本质仍是进程(在Linux环境下) 进程&#xff1a;独立地址空间&#xff0c;拥有PCB 线程&#xff1a;有独立的PCB&#xff0c;但没有独立的地址空间(共享) 区别&#xff1a;在于是否共…

html前端的几种加密/解密方式

HTML前端的加密解密方式有以下几种&#xff1a; 一、base64加密 Base64编码&#xff1a;Base64是一种将二进制数据转换为可打印字符的编码方式。在前端&#xff0c;可以使用JavaScript的btoa()函数进行Base64编码&#xff0c;使用atob()函数进行解码。 var str "hello…

uniapp发行H5获取当前页面query

阅读uni的文档大致可得通过 onLoad与 onShow()的形参都能获取页面传递的参数&#xff0c;例如在开发时鼠标移动到方法上可以看到此方法的简短介绍 实际这里说的是打开当前页面的参数&#xff0c;在小程序端的时候测试并无问题&#xff0c;但是发行到H5时首页加载会造成参数获取…

掌握mysql,看完这篇文章就够了

1.mysql 学习数据库就是学习数据库管理系统&#xff08;一个数据管理系统可以管理多个数据库&#xff09; 安装 安装版本&#xff1a;mysql -installter -community-5.7.41.0.msl 流程 1.custom自定义安装 2.选择安装MySQl Server 5.7.41 - x64 3.默…

c++ 常用新特性总结【c++11】,【c++14】,【c++17】,【c++20】

文章目录 常用的c11新特性1.自动推导类型(auto)2.lambda表达式3.智能指针4.范围for循环5.右值引用 - 移动语义6.类型别名7.constexpr8.static_assert(静态断言)9.nullptr10.列表初始化11.继承构造函数12.显示虚函数重载(override)13.final14.变长模板参数15.新的容器与算法16.强…

代码随想录算法训练营第四十八天|583. 两个字符串的删除操作,72. 编辑距离

系列文章目录 代码随想录算法训练营第一天|数组理论基础&#xff0c;704. 二分查找&#xff0c;27. 移除元素 代码随想录算法训练营第二天|977.有序数组的平方 &#xff0c;209.长度最小的子数组 &#xff0c;59.螺旋矩阵II 代码随想录算法训练营第三天|链表理论基础&#xff…

第三方神秘顾客调查:如何选择专业的营业厅神秘顾客公司

选择专业的营业厅神秘顾客公司时&#xff0c;确实需要考虑多个因素&#xff0c;以确保您合作的公司能够为您提供高质量的服务和有价值的反馈。以下是选择营业厅神秘顾客公司时应考虑的关键因素&#xff1a; 1、公司声誉与经验&#xff1a;选择在行业内有良好声誉和丰富经验的神…

内容管理平台原来这么好用,优秀企业必备

内容管理平台是企业的强有力支持者&#xff0c;它可以使企业对旗下的各种网站、应用和其他数字内容进行集中管理&#xff0c;有效提高工作效率。对于企业的运营、市场推广和客户服务等各方面都有着重要的影响。今天&#xff0c;我们就来推荐三款值得尝试的内容管理平台。 首先…

论文的引用书写方法

前置操作 1、全选文献 2、在开始选项卡 段落功能区 选择编号功能 3、设置编号格式 [1] 论文的引用 1、光标放在需要引用论文的地方 2、选择引用选项卡 点击交叉引用 3、引用类型为编号项 引用内容为段落编号 选择需要的第几条参考文献

备战蓝桥杯---动态规划的一些思想2

话不多说&#xff0c;直接看题&#xff1a; 1.换根DP&#xff1a; 我们肯定不能对每一个根节点暴力求&#xff0c;我们不妨先求f[1]&#xff0c;我们发现当他的儿子作为根节点时深度和为f[1](n-cnt[i])-cnt[i](cnt[i]表示以i为根的节点数&#xff09;&#xff0c;这样子两遍DFS…

论文阅读:Diffusion Model-Based Image Editing: A Survey

Diffusion Model-Based Image Editing: A Survey 论文链接 GitHub仓库 摘要 这篇文章是一篇基于扩散模型&#xff08;Diffusion Model&#xff09;的图片编辑&#xff08;image editing&#xff09;方法综述。作者从多个方面对当前的方法进行分类和分析&#xff0c;包括学习…

Python exec 函数解析:探索动态代码执行的无限可能!

在 Python 中&#xff0c;exec() 是一个内置函数&#xff0c;用于执行储存在字符串或文件中的 Python 代码。这个函数的灵活性使得它在某些情况下成为一种有用的工具&#xff0c;但也因为其潜在的安全风险而需要谨慎使用。本文将深入探讨 exec() 函数的使用方法、注意事项以及适…

P10095 [ROIR 2023 Day 1] 斐波那契乘积

难度&#xff1a;普及/提高- 题目背景 翻译自 ROIR 2023 D1T2。 斐波那契数指斐波那契数列&#xff08;f0​1,f1​1,fi​fi−2​fi−1​&#xff09;中出现的数。 题目描述 给定一个自然数 n&#xff0c;求出将其表示为大于 1 的斐波那契数的乘积的方式数量。 输入格式 …

微信小程序-可以用区域

简介 movable-view和movable-area是可移动的视图容器&#xff0c;在页面中可以拖拽滑动。 本篇文章将会通过该容器实现一个常用的拖拽按钮功能。 使用效果 代码实现 side-view.wtml 布局见下面代码&#xff0c;left view为内容区域&#xff0c;right view为操作按钮&a…