前言
form表单里有文件,比如图像文件、普通文本文件、音频视频文件,该怎么办?
解决方案总的有两种:
- 使用formData实现文件和文本同时提交
- 先ajax上传文件,返回文件url,再和文本一起提交,我称作伪提交。
本文主要介绍第二种伪提交方案,formData使用教程已在下方列出。
https://developer.mozilla.org/zh-CN/docs/Web/API/FormData/Using_FormData_Objects
正文
1、本文开发环境:
1. spring boot
2. mysql
3. java
4. thymeleaf模板引擎
5. layui库
2、layui使用教程
注:layui有一个upload模块,特别好用,本文就是使用upload模块完成了目标。官方文档对于upload模块的介绍很详细,所以我建议你好好研究研究官方文档,再看我的实例不迟!
layui模块的加载
http://www.layui.com/doc/
图片/文件上传 - layui.upload
http://www.layui.com/doc/modules/upload.html#choose
3、前后台代码
前端页面代码:
<form class="layui-form" enctype="text/plain">
<div class="layui-form-item">
<label class="layui-form-label" >名称</label>
<div class="layui-input-block">
<input name="name" lay-verify="name" autocomplete="off" placeholder="请输入标题" class="layui-input" type="text"/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">照片</label>
<div class="layui-input-block">
<button type="button" class="layui-btn" id="upload1">上传图片</button>
<input type="hidden" id="img_url" name="img" value=""/>
<div class="layui-upload-list">
<img class="layui-upload-img" width="100px" height="80px" id="demo1"/>
<p id="demoText"></p>
</div>
</div>
</div>
<div class="layui-form-item" style="text-align: center;">
<button type="submit" class="layui-btn" onclick="update" value="保存"/>
<button class="layui-btn" lay-submit="" lay-filter="*" >立即提交</button>
</div>
</form>
让我们看看下面这段涉及文件上传的代码。div里包含有一个button,一个隐藏的input(用于保存文件url),还有专门预览的div。
<div class="layui-input-block">
//上传按钮
<button type="button" class="layui-btn" id="upload1">上传图片</button>
//隐藏的input
<input type="hidden" id="img_url" name="img" value=""/>
//预览区域
<div class="layui-upload-list">
<img class="layui-upload-img" width="100px" height="80px" id="demo1"/>
<p id="demoText"></p>
</div>
</div>
先上效果图
好了,现在我们继续,上js代码。在这段js代码里,最核心的事情只有三件
- 加载upload上传模块
- 给我的button加上上传文件的功能
- 上传成功后,将返回的url保存到隐藏的input中
<script type="text/javascript" th:inline="javascript">
layui.use('upload', function(){
var upload = layui.upload
, $ = layui.jquery;
var uploadInst = upload.render({
elem: '#upload1' //绑定元素
,url: /*[[@{/upload/img}]]*/'' //上传接口
,before: function(obj){
//预读本地文件示例,不支持ie8
obj.preview(function(index, file, result){
$('#demo1').attr('src', result); //图片链接(base64)
});
}
,done: function(res){
//如果上传失败
if(res.code > 0){
return layer.msg('上传失败');
}
//上传成功
alert("上传成功"+res.url);
document.getElementById("img_url").value = res.url;
}
,error: function(){
//演示失败状态,并实现重传
var demoText = $('#demoText');
demoText.html('<span style="color: #FF5722;">上传失败</span> <a class="layui-btn layui-btn-mini demo-reload">重试</a>');
demoText.find('.demo-reload').on('click', function(){
uploadInst.upload();
});
}
});
});
</script>
文件上传Controller
@Controller
@MultipartConfig
public class FileUploadController {
@RequestMapping(value = "/upload/img" , method = RequestMethod.POST)
@ResponseBody
public Map<String, Object> upload(HttpServletRequest servletRequest,
@RequestParam("file") MultipartFile file
) throws IOException {
//如果文件内容不为空,则写入上传路径
if (!file.isEmpty()) {
//上传文件路径
String path = "/home/jian/Desktop/qingyunV2/qingyunv2/src/main/resources/static/images";
System.out.println("文件名称"+file.getOriginalFilename());
//上传文件名
String filename = file.getOriginalFilename();
File filepath = new File(path, filename);
//判断路径是否存在,没有就创建一个
if (!filepath.getParentFile().exists()) {
filepath.getParentFile().mkdirs();
}
//将上传文件保存到一个目标文档中
File file1 = new File(path + File.separator + filename);
file.transferTo(file1);
Map<String, Object> res = new HashMap<>();
//返回的是一个url对象
res.put("url", file1);
return res;
} else {
return Result.failure();
}
}
}
至此文件上传任务已经完成了,现在表单中隐藏的input已经保存了文件的url,那么,接下来就是简单的纯文本form提交。这个不难,用ajax提交行,正常提交也可以,随意。下面,我仅仅贴出代码。
ajax提交纯文本form
<!--要给当前脚本加上th:inline="javascript",tymeleaf才能生效。self.location = /*[[@{/sys_seller/find}]]*/'';-->
<script type="text/javascript" th:inline="javascript">
layui.use(['form', 'layedit'], function(){
var form = layui.form
, layer = layui.layer
, $ = layui.jquery;
form.on('submit(*)', function (data) {
$.ajax({
type: 'POST',
url: /*[[@{/sys_seller/add}]]*/'',
dataType: 'json',
data: data.field,//往后台发送的是data.field,即一个{name:value}的数据结构
async: true,
success: function (result) {
if (result.code == 0) {
layer.msg('保存成功', {icon: 1, time: 1000});
setTimeout(function () {
self.location = /*[[@{/sys_seller/find}]]*/'';
}, 800);
} else {
layer.msg('保存失败!' + result.msg, {icon: 2, time: 1000});
}
},
error: function (result, type) {
layer.msg('保存失败!', {icon: 2, time: 1000});
}
});
});
return false;
});
</script>
保存信息Controller
@RequestMapping(value = "/sys_seller/add")
@ResponseBody
public Result add(@RequestParam("name") String name ,
@RequestParam("managername") String managername,
@RequestParam("phone") String phone,
@RequestParam("tel") String tel,
@RequestParam("remark") String remark,
@RequestParam("sellarrange") String sellarrange,
@RequestParam("province") String province,
@RequestParam("city") String city,
@RequestParam("address") String address,
@RequestParam("img") String img
) throws IOException
{
Sellers seller = new Sellers();
seller.setName(name);
seller.setManagerName(managername);
seller.setPhone(phone);
seller.setTel(tel);
seller.setRemark(remark);
seller.setSellArrange(sellarrange);
seller.setProvince(province);
seller.setCity(city);
seller.setAddress(address);
seller.setImgurl(img);
System.out.println(seller.toString());
qingYunService.saveSeller(seller);
return Result.success();
}
小结
本文只做为一个引子,过多的东西我也说不明白,希望这些对你有所帮助。如果你想搞清整个提交细节的话,你需要了解@ResponseBody
、Ajax原理
等基础知识。你需要打好基础,才会有万丈高楼平地起!