springboot + thymeleaf + axios 异步上传头像-预览头像-更新并删除原文件


前言

我做的毕设里面的用户页面需要上传头像,现在把详细的业务流程和实现写在这里,供大家参考一下。


有一些细节的前端问题自己解决叭,不然太多了。

一.业务流程

  1. 上传文件并校验文件格式,文件大小,如果都通过则预览文件。
  2. 点击上传之后,更新前端头像,后端保存图片并删除原图片。

二.实现步骤

1.前端内容

先展示一下我的前端页面。
因为我使用jQuery写的js,页面用了bootstrap,也用了它的弹窗插件bootbox,模板引擎用的是thymeleaf,是使用axios做异步的…
在这里插入图片描述

1.1 文件校验并预览

设置的全局变量。

	var file; // 定义一个全局变量,为一个文本选择器。
	var chooseImage; // 用于上传的文件
	file = $('<input type="file" />'); // 这样file就是jquery创建的一个文本选择器,但是因为我们并没有把它加载到页面上,所以是不可见的。
	// button的单击事件 
	$('#chooseImg').click(function(){
		// 启动文件选择
		file.click();
	});

	// 选择好文件后,获取选择的内容
	file.change(function(e){
		var select_file = file[0].files[0];
		
		// 校验文件名称
		var file_path = file.val();
		var extStart = file_path.lastIndexOf("."); // 按.分隔文件名称
		var ext = file_path.substring(extStart, file_path.length).toUpperCase(); // 取出后缀并转为大写
		if (ext != ".BMP" && ext != ".PNG" && ext != ".JPG" && ext != ".JPEG") {
			bootbox.alert({
			    size: "small",
			    title: "提示",
			    message: "图片仅限于bmp,png,jpg,jpeg的格式!",
				buttons: {
					ok: {
						label: '确认',
						className: 'btn-primary'
					}
				},
			    callback: function(){ /* your callback code */ }
			})
			return false;
		}
		
		// 校验文件大小
		if (select_file.size > 1048576) {
			bootbox.alert({
			    size: "small",
			    title: "提示",
			    message: "图片大小不能超过1M!!",
				buttons: {
					ok: {
						label: '确认',
						className: 'btn-primary'
					}
				},
			    callback: function(){ /* your callback code */ }
			})
			return false;
		}
		
		chooseImage = select_file; // 赋值给全局变量 --> 用来做上传的操作

				// 展示到页面
                 var reader = new FileReader();// 读取文件URL
                 reader.readAsDataURL(chooseImage);
                 reader.onload = function() {
                     // 读取的URL结果:this.result
                     $("#re_headImg").attr("src", this.result).show();
                 }

		$("#uploadImg").removeClass("update-head-msg-bt-dis");
		$("#uploadImg").removeAttr("disabled");
		$("#uploadImg").attr("title","选择提交即可上传该图片文件作为头像.");
	});
});

这段代码总体就是三步走,因为我是代码中生成input,它的type为file,所以页面是无法显示,用一个全局变量来接收,做上传使用 -> chooseImage (就是它),第一步就是校验它的文件格式,用substring分割字符换,第二步就是校验文件大小,第三步就是回显到页面,具体的业务根据自己的来设计。

得到的效果如下所示。
在这里插入图片描述

1.2 文件的提交并上传

我在上面对提交按钮设置了disabled,在选择完文件后removeAttr删除它的属性,接下来对form表单进行异步提交, 设置了 event.preventDefault(); 使事件无效,单纯用来异步。

// 头像上传提交事件
 $("#uploadHeadImg_form").submit(function () {
			event.preventDefault();
			var formData = new FormData(); // 要提交的内容封装进formdata
			formData.append("file", chooseImage);
			formData.append('userId', [[${userInfo.id}]])
			axios({
			method: 'post',
			url: '/uploadImage/uploadHeadImg',
			data: formData
			})
         .then(function (response) {
             if (response.data.state == 0) { // 说明上传失败
                 bootbox.alert({
                     size: "small",
                     title: "修改提示",
                     message: "上传头像失败",
                     buttons: {
                         ok: {
                             label: '确认',
                             className: 'btn-primary'
                         }
                     },
                     callback: function(){ /* your callback code */ }
                 })
             } else if (response.data.state == 1) { // 说明添加成功

                 // 更新页面数据
                 var reader = new FileReader();// 读取文件URL
                 reader.readAsDataURL(chooseImage);
                 reader.onload = function() {
                     // 读取的URL结果:this.result
                     $("#avatar_img").attr("src", this.result).show(); // 异步更新页面上的头像图片
                     $("#local_headImg").attr("src", this.result).show(); // 异步更新页面上的头像图片
                     $("#uploadImg").addClass("update-head-msg-bt-dis");
                     $("#uploadImg").attr("disabled","disabled");
                     $("#uploadImg").attr("title","请先选择要上传的图片文件.");
                 }

                 bootbox.alert({
                     size: "small",
                     title: "修改提示",
                     message: "上传头像成功",
                     buttons: {
                         ok: {
                             label: '确认',
                             className: 'btn-primary'
                         }
                     },
                     callback: function(){ /* your callback code */ }
                 })
             }

         })
         .catch(function (error) {
             console.log(error);
         });
 });

这段代码就是做异步提交工作,如果成功则更改页面属性,失败则弹窗报错。

2.后端内容

2.1 依赖文件

		<!--thymeleaf模板引擎-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--fileupload-->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3</version>
        </dependency>

2.1配置文件

controller接收参数,文件和要更改头像用户的id,使用MultipartFile接收文件。逻辑比较简单,大家看一下就行了。
我将文件路径都写在全局配置文件application.properties

#文件上传地址
file.upload.path.realPath=D://idea_springBoot_place/second-hand-website/src/main/resources/static/upload/
file.upload.path.relativePath=/upload/**

在通过@configurationProperties来通过配置文件来解耦。

@Component
@ConfigurationProperties(prefix = "file.upload.path")
public class MyUploadPathProperties {

    /**
     * 文件保存路径
     */
    private String realPath;

    /**
     * 文件保存相对路径
     */
    private String relativePath;

    public String getRealPath() {
        return realPath;
    }

    public void setRealPath(String realPath) {
        this.realPath = realPath;
    }

    public String getRelativePath() {
        return relativePath;
    }

    public void setRelativePath(String relativePath) {
        this.relativePath = relativePath;
    }
}

这里是实现文件上传和删除的主要逻辑代码。
这是controller的逻辑,就是通过File类来保存和删除。

@Controller
@RequestMapping("/uploadImage")
public class UploadImageController {

    @Autowired
    MyUploadPathProperties myUploadPathProperties;

    @Autowired
    UserService userService;

    @ResponseBody
    @PostMapping("/uploadHeadImg")
    public Object uploadHeadImg (MultipartFile file, Integer userId) {
        String oldName = file.getOriginalFilename(); // 获取上传文件名
        // path = D://idea_springBoot_place/second-hand-website/src/main/resources/static/upload/headImg/
        String path = myUploadPathProperties.getRealPath() + "headImg/"; // 定义上传文件路径
        String fileName = changeName(oldName); // 改名
        String rappendix = "/upload/headImg/" + fileName; // 文件相对路径
        // File.separator +
        fileName = path + fileName; // 文件绝对路径

        File file1 = new File(fileName); // 新建文件
        if (!file1.exists()) {
            //先得到文件的上级目录,并创建上级目录,在创建文件
            file1.getParentFile().mkdir();
            try {
                //创建文件
                file1.createNewFile();
            } catch (IOException e) {
                throw new UpLoadException("创建文件失败!");
            }
        }
        // 写入文件
        try {
            file.transferTo(file1);
        } catch (IOException e) {
            throw new UpLoadException("写入文件失败!");
        }
        System.out.println(rappendix);
        System.out.println(file1);

        //-------------------------------
        // 删除原文件
        String oldPath = userService.findById(userId).getHeadImg();
        String oldFileName = myUploadPathProperties.getRealPath() + oldPath.substring(8); // 从 /upload/ 后面开始拼接
        if (!oldPath.equals("/upload/headImg/default.jpg")) { // 默认头像不删除
            if (!delete(oldFileName)) {
                throw new UpLoadException("删除原文件失败");
            }
        }


        // ------------------------------
        // 操作数据库修改
        userService.updateHeadImg(userId, rappendix);

        return new JsonResult(rappendix);

    }

    /**
     * 改名
     * @param oldName
     * @return
     */
    public static String changeName(String oldName){
        Random r = new Random();
        Date d = new Date();
        String newName = oldName.substring(oldName.indexOf('.'));
        newName = r.nextInt(99999999) + d.getTime() + newName;
        System.out.println(newName);
        return newName;

    }

    /**
     * 删除文件
     * @param filePath
     * @return
     */
    public static Boolean delete(String filePath) {
        File file = new File(filePath);
        if (file.exists()) {
            file.delete();
            System.out.println("===========删除成功=================");
            return true;
        } else {
            System.out.println("===============删除失败==============");
            return false;
        }
    }

}

在service层就是修改user表中的img路径。

得到效果如下所示
在这里插入图片描述

结语

如果有什么问题请给我留言吧,一起互相进步互相学习。

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

舍其小伙伴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值