前言
我做的毕设里面的用户页面需要上传头像,现在把详细的业务流程和实现写在这里,供大家参考一下。
有一些细节的前端问题自己解决叭,不然太多了。
一.业务流程
- 上传文件并校验文件格式,文件大小,如果都通过则预览文件。
- 点击上传之后,更新前端头像,后端保存图片并删除原图片。
二.实现步骤
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路径。
得到效果如下所示
结语
如果有什么问题请给我留言吧,一起互相进步互相学习。