spring boot + vue实现图片上传及展示

转载:https://blog.csdn.net/weixin_40337982/article/details/84031778

   其中一部分对我很有帮助 转载记录下

 

首先,html 页面:

    <!--form 中是要加这个 enctype 的 -->
    <form class="form-horizontal" enctype="multipart/form-data">
&lt;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>&gt;
    &lt;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>&gt;图片&lt;/div&gt;
        &lt;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>&gt;
        &lt;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>&gt;
                &lt;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> /&gt;
            &lt;/div&gt;
            &lt;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>&gt;
            &lt;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>/&gt;
            &lt;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>&gt;             
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;</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)">&lt;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)">'&gt;</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>)&gt;<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>)&gt;<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

就可以直接访问到我们的图片了。
项目得启动起来。
只是基本的使用,具体的底层原理,并未深究。
点个赞吧!^_^ !