前言
最近在做一个前后端分离系统,也是闲的无聊做个好玩的练练手。就突然想着之前想了一天的问题,前端怎么去发送图片到后端保存(不是专业前端,轻点喷),图片到底是保存在本地还是存在oss上,保存图片的方式又是什么,这些问题想到我头皮发麻。最后,还是花了一下午的时间写出来了个半成品(最后一步没保存到数据库,后期更新)。
首先我们先来看看效果图:
虽说界面有点丑,但是也还将就吧。
接下来就直接把代码贡献给各位(后期改进点击图片上传)
思路
前端包装一个FormData参数,发送给后端接收,后端定义好实体类和文件,数据交互使用ajax,页面跳转使用Ajax,数据传递使用session。网页展示中,使用FileReader来实时预览。
可能有人问,为什么不用base64编码去保存图片信息,不为什么,因为我不喜欢。。(其实是太长了,每次测试都眼花)
实体类
由于这里是测试,所以我就定义了三个,用户名-username、密码-password、文件名-imgName
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user") // 忽略这里,还没连接数据库。。。
public class Info {
private Integer id;
private String username;
private String password;
private String imgName;
}
前端登录层
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script th:src="@{style.js}"></script>
</head>
<body>
<form id="form-data">
用户名:<input type="text" name="username" placeholder="用户名"><br>
密码:<input type="password" name="password" placeholder="密码"><br>
头像:<input type="file" accept="*/*" name="file" id="FileImg" onchange="xmTanUploadImg(this)">
<img src="" alt="默认头像地址(可以自己填)" id="avarimgs" style="border-radius: 50%" width="200px" height="200px">
<input type="button" value="注册" id="registerBtn" onclick="reg()">
</form>
</body>
</html>
function xmTanUploadImg(obj) {
var file = obj.files[0];
console.log("obj:" + obj);
console.log("file:" + file);
console.log("fileName:" + file.name)
console.log("file.size = " + file.size);
var reader = new FileReader();
reader.onload = function (e) {
console.log(e)// ProgressEvent 对象,里面的target.result就是base64编码
console.log("成功读取....");
var img = document.getElementById("avarimgs");
img.src = e.target.result;
//或者 img.src = this.result; //e.target == this
}
reader.readAsDataURL(file)
}
function reg() {
let form = new FormData($("#form-data")[0])
console.log(form)
$.ajax({
//接口地址
url: 'submit',
type: 'POST',
data: form,
async: false,
cache: false,
contentType: false,
processData: false,
success:function (data) {
console.log(data)
console.log(data.imgName);
sessionStorage.setItem("img_name",data.imgName);
window.location='/info'
}
});
}
后端控制层
@Controller
@ResponseBody
public class FileController {
@RequestMapping(value = "/submit", method = RequestMethod.POST)
public Info submit(MultipartFile file,Info info)
throws Exception {
//这里就可以获取里面的上传过来的数据了
//做一些存库操作,以及返回的数据
String filename = file.getOriginalFilename();
System.out.println(filename);
String filePath = System.getProperty("user.dir")+"\\src\\main\\resources\\static\\img";
if (!new File(filePath).exists()){
new File(filePath).mkdirs();
}
File dest = new File(filePath + File.separator + info.getUsername()+"_"+filename);
try {
file.transferTo(dest);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(info);
info.setImgName(info.getUsername()+"_"+filename);
return info;
}
}
我在后端由于要保存用户头像,所以命名为了防止冲突,直接暴力的使用用户名加上图片文件名进行保存,这样可以很大程度上保证用户的头像唯一(或者在登录的时候直接加一个判断,先保证用户名在数据库中唯一,因为我自己在设计的时候用的主要是一个别名而不是用户名,所以我就没有加)
保存目录不能直接写死路径,假如你的项目需要部署在服务器上,那么就会直接报找不到文件的错误。所以我借用了MyBatis-plus的写法,用了当前系统目录;
踩的坑
在测试的时候,由于第一次上传上去之后图片不能立即显示,需要重启服务器。这个坑折磨了我半个小时,最后看了一眼网上大佬们的做法,加一个资源映射就完美的解决了。确实,这个很nice。所以我也给大家:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
System.out.println("图片配置生效");
String filePath = System.getProperty("user.dir")+"\\src\\main\\resources\\static\\img\\";
System.out.println(filePath);
registry.addResourceHandler("/img/**").addResourceLocations("file:"+filePath);
}
}
依赖问题
很简答,我没用什么很花里胡哨的操作。如果你是直接复制这个demo的话,只需要加一个thymeleaf就行,配置文件不用谢任何东西。
这个也是缠了我好几天的问题了,我i也终于解决了,啊,爽
最后给一张结构图,仅供参考:
如果对你有帮助,请尽情留下你的评论和点赞,我不会嫌弃的哦。
如果哪儿有值得改进的地方,也请告诉我,我会马上加以改进;
谢谢你这么忙还来看我的文章,靓仔!