Vue+Springboot实现头像上传功能

Vue+Springboot实现头像上传功能

前言

最近在着手一个前后端分离的项目,前端用的Vue+ElementUI,后端则是使用Springboot+mybatis实现的。由于本人是第一次完全自己一人编写前后端,所以记录下自己遇到的问题。如果说你也在为上传文件这样一个功能而头疼,那么可以看看我写的这篇文章,希望可以帮到你。废话不多说,咱们直接进入正题。

前端部分

页面代码

这里用了ElementUI的upload组件,主要是样式比自己写的好看点,用标记其实也是一样的,主要注意下在提交文件的时候的数据格式!!!

<el-upload
   ref="upload"
   class="avatar-uploader"
   action="#"
   accept="image/png,image/jpg,image/jpeg"
   :auto-upload="true"
   :limit="1"
   :show-file-list="false"
   :before-upload="beforeAvatarUpload"
   :http-request="uploadHead"
   :on-success="handleAvatarSuccess"
 >
   <img v-if="userInfo.headImage" :src="userInfo.headImage" class="avatar">
   <i v-else class="el-icon-plus avatar-uploader-icon"></i>
 </el-upload>

js代码

文件在上传的时候需要用FormData格式的数据发送请求,这里用到了vue-axios实现请求示例,使用ajax的小伙伴也是一样的哦!只要在ajax的data里传入FormData格式的数据即可。

async uploadHead(f) {
   // console.log(f);  // 感兴趣的小伙伴可以在控制台输出下这里
   let fd = new FormData(); //通过form数据格式来传
   fd.append("file", f.file); 
   // console.log(fd.get('file')); 
   let res = await this.$http.uploadHead(fd, {
     headers: { 'Content-Type': 'multipart/form-data' }
   });
   console.log(res);
 }

这里需要注意的是我们使用fd.append("file",f)是不行的,为什么呢,改成fd.append(“file”,f)我们发送下请求
在这里插入图片描述
可以看到请求头里确实发送了一个FormData的数据,但是后端在处理这样的请求时会出现400错误,我们需要的并不是这样的一个数据,接下来感兴趣的小伙伴可以在控制台输出一下我们在前端选中的文件f
在这里插入图片描述
可以看到输出了一个对象,而这个对象里又包含了一个file对象,这才是我们需要传递的数据,所以在发送请求时需要将这个file对象传至后端,使用“对象.属性名”的方式即可获取到相应的值,我们再来发送一次请求
在这里插入图片描述
可以看到请求参数变成二进制格式,这就是我们需要的数据

后端部分

由于本人对java并不熟练,所以对于后端如何处理文件请求实在是一概不知,本着勤奋好学的态度,最终,找到了这样一种方式

@PostMapping("/uploadHead")
@ResponseBody
public ServerResponse uploadHead(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
	String path = request.getServletContext().getRealPath("/"); // 获取服务器所在地址
	String url = request.getContextPath() + "/headImage/";
	File filePath = new File(path);
	System.out.println("文件的保存路径:" + path);
	if (!filePath.exists() && !filePath.isDirectory()) {
    	System.out.println("目录不存在,创建目录:" + filePath);
    	filePath.mkdirs(); // mkdir()不会创建目录,找不到相应路径时返回false;而mkdirs()当目录不存在时则会创建相应目录
	}
	//获取原始文件名称(包含格式)
    String originalFileName = file.getOriginalFilename();
    //获取文件类型,以最后一个`.`为标识
    String type = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
    HttpSession session = request.getSession();
    String userId = Integer.toString((Integer)session.getAttribute("userId"));
    String fileName = userId + "."+ type; // 新文件名,这里可以根据需要改名
    //在指定路径下创建一个文件
    File targetFile = new File(path, fileName); // 未使用outputStream.write()的时候,是一个File对象,保存在内存中,硬盘中看不到,但是可以使用这个对象
    try {
        // 使用springmvc的transferTo方法上传文件
        file.transferTo(targetFile);
        UserInfo userInfo = new UserInfo();
        userInfo.setHeadImage(url + fileName);
        userInfo.setUserId((Integer)session.getAttribute("userId"));
        int i = userService.updateUserInfo(userInfo);
        if (i != 0) {
            return ServerResponse.createBySuccess("头像上传成功", url + fileName);
         }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return ServerResponse.createByError("头像上传失败");
}

处理成功后,我们来看数据库是否保存了相应路径,以及文件系统中是否保存了相应文件
在这里插入图片描述
在这里插入图片描述
这是上面获取到的路径,这个路径是springboot内置的tomcat的临时地址,所以每次启动springboot项目的时候,目录名字都不一样。在此路径下确实保存了相应的文件,数据库也确实保存了相应路径。
但是这样一条路径,前端要如何访问呢?
这里就要在前端设置一下代理了,在vue.config.js里配置跨域

module.exports = {
    devServer: {
        open: false,// 自动打开浏览器
        host: 'localhost',
        port: 8080,
        https: false,
        hotOnly: false,
        disableHostCheck: true,//Invalid Host header
        proxy: { // 配置跨域
            '/alumni': {
                target: 'http://localhost:8081', // 这是后端地址
                ws: true,
                changOrigin: true,
                pathRewrite: {
                  '^/alumni': '/alumni' 
                }  
            }
        },
        before: app => { }
    }
}

一切准备就绪之后,打开我们的页面,查看下头像是否上传成功

在这里插入图片描述
可以看到空空如也,为什么呢?代理也设置好了,前端为什么无法访问图片呢?为了一探究竟,我们在地址栏里访问下localhost:8081/alumni/headImage/2.png,结果却是可爱的404页面。

至于原因是为什么我也说不清楚,只知道如果是ssm的项目,使用我们自己本地的Tomcat的时候,request.getServletContext().getRealPath("/")获取到的就是项目的地址,即该项目的服务器地址(暂且这样理解吧);而我们上面也提到了springboot返回的却是一个随机的地址,每次启动项目的时候目录名字都不一样,这样一个地址在项目发布上线之后可以不用管(上面的方法可以不用改),但是在开发阶段则不行;另外,springboot的项目默认的静态资源需要放置在resources的static目录下,在此目录下的文件可通过后端地址直接访问

所以,需要将request.getServletContext().getRealPath("/")改成ResourceUtils.getURL("classpath:").getPath() + "static/headImage/",这样在开发阶段就可以访问到了。

第一次写博客,可能有很大表达不清晰的地方,希望大家见谅,也希望能够帮助到大家。

发布了1 篇原创文章 · 获赞 1 · 访问量 42

猜你喜欢

转载自blog.csdn.net/Xiaoming985/article/details/104974978
今日推荐