spring boot + vue实现图片上传及展示
转载:https://blog.csdn.net/weixin_40337982/article/details/84031778
其中一部分对我很有帮助 转载记录下
首先,html 页面:
<!--form 中是要加这个 enctype 的 --> <form class="form-horizontal" enctype="multipart/form-data"><div v-<span style="color: rgba(0, 0, 255, 1)">if</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">menu.type == 1</span><span style="color: rgba(128, 0, 0, 1)">"</span> <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">form-group</span><span style="color: rgba(128, 0, 0, 1)">"</span>> <div <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">col-sm-2 control-label</span><span style="color: rgba(128, 0, 0, 1)">"</span>>图片</div> <div <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">col-sm-10</span><span style="color: rgba(128, 0, 0, 1)">"</span>> <div <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ui-upfile</span><span style="color: rgba(128, 0, 0, 1)">"</span>> <div style=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">width: 150px;height: 140px;display:none;</span><span style="color: rgba(128, 0, 0, 1)">"</span> <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">file-area</span><span style="color: rgba(128, 0, 0, 1)">"</span> /> </div> <input type=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">hidden</span><span style="color: rgba(128, 0, 0, 1)">"</span> name=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">menuImgUrl</span><span style="color: rgba(128, 0, 0, 1)">"</span> <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">menu-image-url</span><span style="color: rgba(128, 0, 0, 1)">"</span> v-model=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">menu.menuImgUrl</span><span style="color: rgba(128, 0, 0, 1)">"</span>> <input type=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">button</span><span style="color: rgba(128, 0, 0, 1)">'</span> <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">btn</span><span style="color: rgba(128, 0, 0, 1)">'</span> value=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">上传图片</span><span style="color: rgba(128, 0, 0, 1)">'</span>οnclick=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">document.getElementById('file').click()</span><span style="color: rgba(128, 0, 0, 1)">"</span> style=<span style="color: rgba(128, 0, 0, 1)">""</span>/> <input type=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">file</span><span style="color: rgba(128, 0, 0, 1)">"</span> <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">menu-image-url</span><span style="color: rgba(128, 0, 0, 1)">"</span> value=<span style="color: rgba(128, 0, 0, 1)">""</span> id=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">file</span><span style="color: rgba(128, 0, 0, 1)">"</span> @change=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">onUpload</span><span style="color: rgba(128, 0, 0, 1)">"</span> style=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">filter:alpha(opacity:0);opacity:0;width:0px</span><span style="color: rgba(128, 0, 0, 1)">"</span>> </div> </div> </div></pre>
这里要说明一下,由于使用的是 vue,所有这里赋值取值都是使用 v-model,然后这里为什么会有这么多 input 框,
第一个是返回我对象的属性值的;
第二个是手写的一个按钮,因为如果直接使用 input type=file 的话,样式比较丑,还会有未选择文件那个字样 ,可以那个 type=file 的 input 又是必须的。
所以这里我们使用一个 button 去覆盖 type=file 的功能,并且把 type=file 的 input 隐藏起来,这里的核心代码是:opacity:0;
接下来,js 代码:
onUpload(e){ var files = e.target.files[0]; var formFile = new FormData(); formFile.append("file", files); $.ajax({ url: baseURL + 'sys/upload/uploadPic',//这里是请求后台的上传文件接口 type: 'POST', dataType: 'json', cache: false, data: formFile, processData: false, contentType: false, success: function(r){</span><span style="color: rgba(0, 0, 255, 1)">if</span> (r.code === <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">) { vm.menu.menuImgUrl </span>=<span style="color: rgba(0, 0, 0, 1)"> r.fileUrl; $(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">.file-area</span><span style="color: rgba(128, 0, 0, 1)">"</span>).css(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">display</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">block</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">); $(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">.file-area</span><span style="color: rgba(128, 0, 0, 1)">"</span>).html(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)"><img src= '</span><span style="color: rgba(128, 0, 0, 1)">"</span>+ r.fileUrl +<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">'></span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">); }</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">{ alert(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">文件上传失败:</span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> r.msg); } } }); }</span></pre>
由于使用的是 vue,所以这里是写在 methods 下面的。
这里主要是请求后台,把文件传过去,然后返回一个 url, 通过这个 url 我们可以直接访问到图片。
后台 UploadController 类
@RestController @RequestMapping("/sys/upload") public class UploadController extends BaseController {</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">* * 上传图片 * @param file * @param request * @throws IOException </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)"> @RequestMapping( value </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/uploadPic</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">) @ResponseBody </span><span style="color: rgba(0, 0, 255, 1)">public</span> R uploadPic(@RequestParam(value = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">file</span><span style="color: rgba(128, 0, 0, 1)">"</span>, required = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">) MultipartFile file, HttpServletRequest request) throws IOException { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">目前这里是写死的本地硬盘路径</span> String path = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">D:/img</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">; logger.info(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">path:</span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> path); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取文件名称</span> String fileName =<span style="color: rgba(0, 0, 0, 1)"> file.getOriginalFilename(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取文件名后缀</span> Calendar currTime =<span style="color: rgba(0, 0, 0, 1)"> Calendar.getInstance(); String time </span>= String.valueOf(currTime.<span style="color: rgba(0, 0, 255, 1)">get</span>(Calendar.YEAR))+String.valueOf((currTime.<span style="color: rgba(0, 0, 255, 1)">get</span>(Calendar.MONTH)+<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取文件名后缀</span> String suffix = fileName.substring(file.getOriginalFilename().lastIndexOf(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">.</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)); suffix </span>=<span style="color: rgba(0, 0, 0, 1)"> suffix.toLowerCase(); </span><span style="color: rgba(0, 0, 255, 1)">if</span>(suffix.equals(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">.jpg</span><span style="color: rgba(128, 0, 0, 1)">"</span>) || suffix.equals(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">.jpeg</span><span style="color: rgba(128, 0, 0, 1)">"</span>) || suffix.equals(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">.png</span><span style="color: rgba(128, 0, 0, 1)">"</span>)<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> || suffix.equals(".gif")</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">){ fileName </span>= UUID.randomUUID().toString()+<span style="color: rgba(0, 0, 0, 1)">suffix; File targetFile </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> File(path, fileName); </span><span style="color: rgba(0, 0, 255, 1)">if</span>(!targetFile.getParentFile().exists()){ <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">注意,判断父级路径是否存在</span>
targetFile.getParentFile().mkdirs();
}
long size = 0;
//保存
try {
file.transferTo(targetFile);
size = file.getSize();
} catch (Exception e) {
e.printStackTrace();
return R.error("上传失败!");
}
//项目 url,这里可以使用常量或者去数据字典获取相应的 url 前缀;
String fileUrl="http://localhost:8080";
//文件获取路径
fileUrl = fileUrl + request.getContextPath() + "/img/" + fileName;
logger.info("fileUrl:" + fileUrl);
return R.ok().put("fileUrl", fileUrl);
}else{
return R.error("图片格式有误,请上传.jpg、.png、.jpeg 格式的文件");
}} }</span></pre>
这里有个坑,就是由于 spring boot 使用的内置 tomcat, 所以会自动在系统盘下生成一个编译路径,大概是这样的:
C:\Users\69223\AppData\Local\Temp\tomcat-docbase.6718506550492189172.8080
可是把文件放到这个下面,我们无法去正确获取,而且这里的 tomcat 生成的文件夹中间那一段数字,还都是在变化的。具体原因没有细究。
经过一天的百度及个人理解,最终决定使用映射;
在 application.yml 文件中添加要映射的绝对路径,即图片要保存的位置:
#文件上传
cbs:
imagesPath:
file:/D:/img/
yml 文件中格式要求极为严格 ,必须是 4 个空格,tab 键不起作用,直接使用 cbs.imagesPath.file 也报错。
这里的文件绝对路径就是我们上传文件时写的上传路径;
之后编写 WebMvcConfig 配置文件;
@Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter{@Override </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> addViewControllers(ViewControllerRegistry registry) { registry.addViewController(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/</span><span style="color: rgba(128, 0, 0, 1)">"</span>).setViewName(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">forward:/login.html</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">); registry.setOrder(Ordered.HIGHEST_PRECEDENCE); super.addViewControllers( registry ); } </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">* * 在配置文件中配置的文件保存路径 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)"> @Value(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">${cbs.imagesPath}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String mImagesPath; @Bean </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> MultipartConfigElement multipartConfigElement(){ MultipartConfigFactory factory </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> MultipartConfigFactory(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">文件最大KB,MB</span> factory.setMaxFileSize(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">1024MB</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置总上传数据总大小</span> factory.setMaxRequestSize(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">1024MB</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> factory.createMultipartConfig(); } </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">* * 这里是映射文件路径的方法 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)"> @Override </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> addResourceHandlers(ResourceHandlerRegistry registry) { </span><span style="color: rgba(0, 0, 255, 1)">if</span>(mImagesPath.equals(<span style="color: rgba(128, 0, 0, 1)">""</span>) || mImagesPath.equals(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">${cbs.imagesPath}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)){ String imagesPath </span>= WebMvcConfig.<span style="color: rgba(0, 0, 255, 1)">class</span>.getClassLoader().getResource(<span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">).getPath(); </span><span style="color: rgba(0, 0, 255, 1)">if</span>(imagesPath.indexOf(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">.jar</span><span style="color: rgba(128, 0, 0, 1)">"</span>)><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">){ imagesPath </span>= imagesPath.substring(<span style="color: rgba(128, 0, 128, 1)">0</span>, imagesPath.indexOf(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">.jar</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)); }</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span>(imagesPath.indexOf(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">classes</span><span style="color: rgba(128, 0, 0, 1)">"</span>)><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">){ imagesPath </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">file:</span><span style="color: rgba(128, 0, 0, 1)">"</span>+imagesPath.substring(<span style="color: rgba(128, 0, 128, 1)">0</span>, imagesPath.indexOf(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">classes</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)); } imagesPath </span>= imagesPath.substring(<span style="color: rgba(128, 0, 128, 1)">0</span>, imagesPath.lastIndexOf(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/</span><span style="color: rgba(128, 0, 0, 1)">"</span>))+<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/img/</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">; mImagesPath </span>=<span style="color: rgba(0, 0, 0, 1)"> imagesPath; } registry.addResourceHandler(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/img/**</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">).addResourceLocations(mImagesPath); super.addResourceHandlers(registry); } }</span></pre>
addResourceHandlers() 方法是映射文件路径的方法;
这里我们还需要在权限配置类中添加如下,即放开 img 下的权限控制,否则会涉及到权限,被拦截;
filterMap.put("/img/**", "anon");
截止到这里,我们的上传图片基本已经完成了,接下来就可以进入测试阶段。
我们把文件上传到 D 盘下面的 img 文件夹,上传成功之后,我们使用:
http://localhost:8080/ 项目名 /img/3b13ad02-3812-4c39-880d-799172801284.png
就可以直接访问到我们的图片了。
项目得启动起来。
只是基本的使用,具体的底层原理,并未深究。
点个赞吧!^_^ !