图片上传(学习1)单图
项目开发不可避免的要用到图片上传,最近也上网看了一些插件的引用,不过都不是很明白.而且感觉(...有点小尴尬).所以就决定从最简单的实现开始,慢慢的自己封装功能.这样自己完善起来也方便,并且自我感觉,对于后台开发来讲(当然,现在的主要还是写交互),自己写这种上传组件的过程,也是一种学习的过程.和自我提升的过程.
1.先介绍下所使用的框架,后台controller是用的springboot,mybatis框架,前端交互则是用的thymeleaf.页面则是HTML,这里不对thymeleaf做太多介绍(毕竟本人也是刚接触).
2. 纯form表单的提交,当然,这种表单提交的方式有很大的漏洞,因为这种上传的方式是读取的input标签的选取的文件内容,对于需要重复选择/做移除的需求,这种表单提交的方式将会显得非常的局限.因为表单提交的图片是input标签最近拉取的文件列表.对于上一次拉取的图片,即便是在HTML中实现了纯前端的预览,可是实际的效果是无法实现的.
当然,对于单图上传来说,这种方式还是可以适用的,只是无法对所上传的图片做额外的处理,比如:在上传的时候自动为图片加水印.(当然,听说是有后台/服务器实现的方法,这还有待研究)
代码如下:
前端HTML
<form th:action="@{表单提交对应的后台路径}"method="post" th:object="${对应的后台表单对象}" enctype="multipart/form-data" > <input class="file" name="pictures" type="file" style="display:none;" multiple accept="image/*" onchange="imagePreview(this)"/>
<!-->input标签的name属性是很关键的,因为后台controller获取数据流就是通过这个name属性获取的<-->
<!-->multiple是声明可选择多图,单图的情况下可去掉 accept="image/*"是声明只可选取图片类型 <-->
</form>
预览JS
function imagePreview(input){
var files = input.files;//获取input标签所选择的图片集合
var html ="";
for (var i = 0; i < files.length; i++) {
var file = files[i];
var reader = new FileReader();
reader.onload = function(e) {
for( var j=0;j<$(".img .fileimg").length;j++) {
// console.log($(".img .fileimg").eq(j).find("img").attr("src"));通过这种方式可获取到已有的图片SRC
if( e.target.result == $(".img .fileimg").eq(j).find("img").attr("src")){//if方法判断图片是否已经选取,可避免重复选择
return false;
}
}
//加入没有重复选择通过fileReader对象即可读取图片的二进制数据,实现预览
html ="<div class='fileimg'><em class='remove'>移除</em><img width='100' height='100' id='pic"+j+"' src='"+e.target.result+"'></div>"
$(".img").append(html);//页面中做回显
};
reader.readAsDataURL(file);//把图片读取为URL数据
}
}
后台对应的映射controller
@RequestMapping("/admin/resource/projectEdit")
@Controller
@MultipartConfig
public class ProjectEditController extends AbstractController{
@RequestMapping(value = "updateOrAddProject" , method = RequestMethod.POST)
public String updateOrAddProject(@RequestParam(value = "pictures") MultipartFile [] pictures) {
//@RequestParam(value = "pictures")中的pictures就是对应的页面中的name="pictures",而此时读取的数据实际上为最近一次通过input标签拉取的图片数据
` }
}
对应上传图片的方法,这里我给写到service层了
public List<Long> addPiture(MultipartFile[] pictures) {
List<Long> newPictureIds = new ArrayList<Long>();
for (MultipartFile picture : pictures) {
/** 获取图片大小判断是否有真的图片上传,因为在几遍不选择图片的情况下,后台的图片数组中length属性也为1 */
Long picSize = picture.getSize();
if(picSize != null && picSize > 0) {
/** 获取图片类型 */
String contentType1 = picture.getContentType();
String pictureType = contentType1.split("/")[1].toString();
/** 图片保存名称 */
String pictureName = System.currentTimeMillis() + "." +pictureType;
/** 获取上传日期 */
String nowDate = DateUtil.dateToString(new Date() , "yyyyMMdd");
/** 文件相对存放路径 */
String uploadFloder = "/upload/" + accountId + "/" + nowDate + "/"+pictureName;
/** 文件保存绝对路径 */
String filePath = fileUploadFolder + accountId +"\\" + nowDate + "\\" + pictureName;
/** 图片所在文件夹路径 */
String picFolderPath = fileUploadFolder + accountId +"\\" +nowDate +"\\" ;
try {
uploadPicture(picture.getBytes() , picFolderPath , pictureName);
}catch (IOException e){
throw new ServiceException("图片上传错误");
}
}else{
continue;
}
}
return newPictureIds;
}
具体执行图片流写入的方法:
public void uploadPicture(byte[] file , String filePath , String fileName) {
File picturePath = new File(filePath);
if(!picturePath.exists()) {
picturePath.mkdirs();
}
FileOutputStream out = null;
try {
out = new FileOutputStream(filePath+fileName);
out.write(file);
out.flush();
out.close();
}catch (IOException e) {
throw new ServiceException("图片上传错误");
}
}