首先先说明一下,我写的代码是jquery和js相结合的,可能有点low。
本次上传我用到了ajaxFileUpload进行文件的上传,我会分为两个部分来说,分别是:(这两个部分其实是互不干扰的,如果你不想用我写的这个控件的效果,那么只需要看后面第二点即可)
1)file控件的美化
传统的file控件如下,这种是非常原始的,很low,用bootstrap的file组件也可以,很美观,那么上传文件的方式就要遵循这个组件的要求,这里,我没有用它,我是自己从新写了一个,会实现不同的效果,虽然也不咋地。
<input type="file" id="images_file" name="images_file">
原始控件图:
2)ajaxFileUpload上传文件的实际操作
这里用这个来做也是为了方便,但是从网上下载了这个js之后有一些问题,后面我做了一些修改,我会说,你要用这个组件直接新建个js,取名为ajaxFileUpload,然后把我贴出来的代码复制进去就行了。
下面进入正题
因为我用的是jsp结合servlet做的,所以在用这两个东西的朋友可以看下,虽然现在没人用jsp了,只是学习用还是可以的。
1)jsp页面的代码
----------file控件部分
效果:
从这里可以看到,按钮换到了右边,是我想要的效果
代码如下:当一个页面中有多个地方要进行文件上传的,那么就需要去修改下面代码中两个<input>的id,同时对两个方法中的参数进行相应的修改
html/jsp:
<label style="margin-left: -5em;margin-right: 2em;color: white;">文件上传</label>
<!-- 下面这个输入框用于在页面显示选取的文件名,传入后台图片的路径地址就传images_name的值到后台-->
<input type="text" class="inputContent" id="file_name" readonly/>
<!-- 下面这个是实际选择文件的file控件,只是隐藏了,在这个标签中调用了一个我自己写的方法,需要传入上面用于显示文件名字的输入框的id,和自身的id-->
<input type="file" id="file_obj" name="file_obj" onchange="fileChoice('file_name','file_obj')" style="display: none">
<!-- 用于可以手动清空显示文件名输入框的内容,也就是上面input--text的内容 -->
<button class="clearFileName" id="clearFileName">×</button>
<!--下面这个按钮是用来触发上面的file控件的,传入上面file控件的id-->
<button type="button" class="btn btn-default btn-sm" onclick="fileUp('file_obj')" >浏览</button>
<br><br style="line-height: 1em">
css:
.inputContent{
background-color: #e3e3e3;
border: none;
display: inline-block;
margin-left: 1em;
height: 2em;
width: 12em;
}
.clearFileName{
height: 2em;
background-color: #e3e3e3;
vertical-align: middle;
border: 0px
}
上面的点击按钮的样式我用到了bootstrap的样式,你也可以自己定义css
这里我需要说下,我在js中写了两个方法用于之后的效果显示,就是上面的fileChoice()和fileUp方法,在上面的代码中,你可以看到有两个<input>,一个type=text,一个type=file;type=text的是用于显示选中之后文件的名字的,type=file的是做了隐藏的,主要是当我点击了按钮之后会触发这个file,实现选择的效果。如下:
点击按钮之后就出现了这个弹出框,就是触发了这个file,用来选择文件的。
文件选择之后,会弹出模态框,点击了模态框的上传按钮之后就是这个效果:
用作显示的input框就是上面的input-----text
下面这个是个模态框,当我们选择了文件之后,就会弹出这个模态框,这个模态框直接复制就可以,是不需要做任何处理的,我已经写好了,上面那串代码可能还要改一下id,这个不需要动,一个页面一个模态框就可以了。
模态框代码如下:
<!--文件上传显示模态框,该模态框一个页面只需要一个就可以了,该区域不用你们管-->
<div class="modal fade" id="fileUpModal" tabindex="-1" role="dialog"
aria-labelledby="imageUp" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">×
</button>
<h4 class="modal-title" id="imageUp">文件上传</h4>
</div>
<div class="modal-body" id="caseDescDiv">
<!--用于保存当前文件使用的为哪个file控件的id -->
<input type="text" id="file_obj_save" style="display: none">
<!--用于保存显示文件名的input输入框的id-->
<input type="text" id="file_name_save" style="display: none">
<p style="text-align: center">
<!-- 如果上传的是图片,用这个显示上传的图片-->
<img class="img" src=""/><br>
<!-- 如果上传的不是图片,用下面这个现实一个随机的图标-->
<img class="img2" src=""/>
<!-- 显示上传的文件的名称-->
<span id="fileNameShow"></span><br>
<!--显示上传状态-->
<span id="fileUpWarn"></span>
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"
id="close_model">关闭
</button>
<button type="button" id="submitBtn" class="btn btn-primary">上传</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal -->
</div>
css:
.img{
width: 30em;
}
.img2{
height: 3em;
}
那么效果图如下:
选择的是图片的效果:
选择的不是图片的其他文件效果:
当我们点击之前的“浏览”按钮之后,并且在选择了相应的文件之后,就会弹出来这么一个模态框,上面有两个按钮,一个关闭,一个上传按钮,到这里,也就是关于file控件的美化部分,因为上传处理是单独的处理,只是对这个上传按钮添加一个点击事件罢了。
效果的js代码如下:
function fileUp(str) {
// 触发file控件的点击事件
document.getElementById(str).click();
}
function fileChoice(fileName, fileWidget) {
// 获得input--file控件对象
var objFileWidget = document.getElementById(fileWidget);
// 获取file上传的文件
var file = objFileWidget.files[0];
// 获取用于显示文件名的input--text输入框
var objFileName = document.getElementById(fileName);
// 给模态框中的隐藏id为file_obj_save的input--text输入框赋值,保存正在使用的input--file控件的id
var file_obj_save = document.getElementById("file_obj_save");
file_obj_save.value = fileWidget;
// 给模态框中的隐藏id为file_name_save的input--text输入框赋值,保存显示文件名输入框的id
var file_name_save = document.getElementById("file_name_save");
file_name_save.value = fileName;
// 给显示文件名的input赋值
objFileName.value = file.name;
//将模态框中的所有用于显示的标签内容清空
$(".img").attr("src", "");
$(".img2").attr("src", "");
document.getElementById("fileNameShow").innerHTML = "";
document.getElementById("fileUpWarn").innerHTML = "";
// 显示文件模态框
$('#fileUpModal').modal('show');
//判断文件是否是图片,如果是图片执行if里面的操作,显示图片和图片名称
if ((file.type).indexOf("image/") != -1) {
// 将图片写入到模态框里显示图片
if (window.FileReader) {
var reader = new FileReader();
reader.readAsDataURL(file);
// 监听文件读取结束后事件
reader.onloadend = function (e) {
//显示图片
$(".img").attr("src", e.target.result); // e.target.result就是最后的路径地址
//显示文件名
document.getElementById("fileNameShow").innerHTML = file.name;
};
}
} else {
//不是图片的话随机显示图标
$(".img2").attr("src", getImg());
//显示文件的名字
document.getElementById("fileNameShow").innerHTML = file.name;
}
}
//随机获得图标地址
function getImg() {
var randomNum = Math.round(Math.random() * 10);
console.log(randomNum);
var img = "";
if (randomNum == 0) {
img = "../static/img/file1.png";
} else if (randomNum == 1) {
img = "../static/img/file2.png";
} else if (randomNum == 2) {
img = "../static/img/file3.png";
} else if (randomNum == 3) {
img = "../static/img/file4.png";
} else if (randomNum == 4) {
img = "../static/img/file5.png";
} else if (randomNum == 5) {
img = "../static/img/file6.png";
} else if (randomNum == 6) {
img = "../static/img/file7.png";
} else if (randomNum == 7) {
img = "../static/img/file8.png";
} else if (randomNum == 8) {
img = "../static/img/file9.png";
} else if (randomNum == 9) {
img = "../static/img/file10.png";
} else if (randomNum == 10) {
img = "../static/img/file11.png";
}
return img;
}
上面这段js就是我之前说过的两个方法,记住这两个方法千万不要写下面这串代码里面,因为这个表示的是页面一来就加载的内容,是动态的内容,而上面的方法是写死的,是静态的,在jsp上是直接调用的这两个方法,所以是静态的,写在这个这串代码的外部就行。这里只是说下,如果你在代码中用到了下面的代码情况下。
我建议:将我写出来的js、css单独写在相应的一个js、css文件中,这样能够实现复用,只需在jsp中引入即可
$(function() {
});
2)ajaxFileUpload进行文件上传
下面就是正经的文件上传部分了,首先说一下,刚才看到了,模态框上有两个按钮,一个关闭,一个上传,那么我就对这两个按钮进行了添加点击事件处理。如果你是直接用的下面这个
<input type="file" id="file" name="file"/>
<button>上传</button>
那么你只需要对这个button添加一个点击事件即可,那么代码都差不多,只需在点击事件方法中调用下面ajaxFileUpload(fileid, url)这个方法即可,这个方法也是我写好的,只需要传入上面file的id和需要传到后台服务器的路径url即可。
下面是代码:包括两个按钮的点击事件,和一个ajaxFileUpload(fileid, url)方法
//以下所有代码都是为文件上传所写的js
$(function () {
//点击jsp上那个叉叉按钮清除文件名显示框的内容
$('#clearFileName').bind("click", function () {
var file_name_save = document.getElementById("file_name_save");
var file_name_save_value = file_name_save.value;
var objFileName = document.getElementById(file_name_save_value);
// 清空用于显示文件名的输入框的内容
objFileName.value = "";
});
//模态框关闭按钮点击操作
$('#close_model').bind("click", function () {
// 获得模态框中保存input---text用于显示文件名的输入框的input输入框的对象,自己去看模态框部分,你就看懂了
var file_name_save = document.getElementById("file_name_save");
var file_name_save_value = file_name_save.value;
var objFileName = document.getElementById(file_name_save_value);
// 清空用于显示文件名的输入框的内容
objFileName.value = "";
// 隐藏文件模态框
$('#fileUpModal').modal('hide');
});
//点击上传按钮后的点击事件
$('#submitBtn').bind("click", function () {
document.getElementById("fileUpWarn").innerHTML = "正在上传中,请稍后。。。。";
// 获得模态框中保存input---file控件id的input输入框的对象
var file_obj_save = document.getElementById("file_obj_save");
// 获得这个对象里面保存的具体的file控件id
var file_obj_save_value = file_obj_save.value;
var url = getPath() + "/upfile";// 获得后台servlet的路径
// 传入input----file的id,和上传路径
ajaxFileUpload(file_obj_save_value, url);// 调用ajax文件上传的方法,该方法是自己写的,自己去看模态框部分,你就看懂了
});
// 用于上传的方法,自己写的
function ajaxFileUpload(fileid, url) {
// 通过id获得input----file这个控件的对象
var fileObj = document.getElementById(fileid);
// 调用ajaxFileUpload的方法了
$.ajaxFileUpload({
url: url, // 用于文件上传的服务器端请求地址
type: 'post',// 提交方式
contentType: 'multipart/form-data',// 提交内容以什么类型提交
data: { // 提交的内容
file: fileObj
},
secureuri: false, // 是否需要安全协议,一般设置为false
fileElementId: fileid, // 文件上传域的ID
dataType: 'json', // 返回值类型 一般设置为json
success: function (data, status) { // 服务器成功响应处理函数
//上传成功后在模态框中显示返回消息
document.getElementById("fileUpWarn").innerHTML = data.information;
//上传成功后1秒后隐藏模态框
setTimeout(function () {
$('#fileUpModal').modal('hide');
}, 1000);
},
error: function (data, status, e) { // 服务器响应失败处理函数
alert(e);
}
});
}
});
在上面中你可看到我去获得后台servlet路径时有一个getPath()方法,代码如下,主要是获得项目的名称
//获得项目名称
function getPath() {
var pathName = window.document.location.pathname;
var projectName = pathName
.substring(0, pathName.substr(1).indexOf('/') + 1);
return projectName;
}
那么在使用ajaxFileUpload上传时要先引用下面这个js
ajaxfileupload.js 代码如下:这个是网上下载的,不过我做了修改的。第一:下载下来的没有handleError这个方法,会报错;第二:在代码最后部分做了修改,不然不能成功,会报错,你拖到代码最下面就能看到。
引入顺序如图:(getPath()方法在commons.js中),最后一个是自己写的js,要在ajaxfileupload.js下面,不然无效,没用bootstrap不用管这个js,如果用了我的效果,这个必须。
用的时候你就新建一个ajaxfileupload.js ,把这个代码复制进去就可以了
jQuery.extend({
handleError: function (s, xhr, status, e) {
// 如果指定了本地回调,则将其触发
if (s.error) {
s.error.call(s.context || s, xhr, status, e);
}
// 触发全局回调
if (s.global) {
(s.context ? jQuery(s.context) : jQuery.event).trigger(
"ajaxError", [xhr, s, e]);
}
},
createUploadIframe: function (id, uri) {
//create frame
var frameId = 'jUploadFrame' + id;
if (window.ActiveXObject) {
var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
if (typeof uri == 'boolean') {
io.src = 'javascript:false';
} else if (typeof uri == 'string') {
io.src = uri;
}
} else {
var io = document.createElement('iframe');
io.id = frameId;
io.name = frameId;
}
io.style.position = 'absolute';
io.style.top = '-1000px';
io.style.left = '-1000px';
document.body.appendChild(io);
return io
},
createUploadForm: function (id, fileElementId) {
//create form
var formId = 'jUploadForm' + id;
var fileId = 'jUploadFile' + id;
var form = $('<form action="" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>');
var oldElement = $('#' + fileElementId);
var newElement = $(oldElement).clone();
$(oldElement).attr('id', fileId);
$(oldElement).before(newElement);
$(oldElement).appendTo(form);
//设置属性
$(form).css('position', 'absolute');
$(form).css('top', '-1200px');
$(form).css('left', '-1200px');
$(form).appendTo('body');
return form;
},
addOtherRequestsToForm: function (form, data) {
// 添加额外的参数
var originalElement = $('<input type="hidden" name="" value="">');
for (var key in data) {
var name = key;
var value = data[key];
var cloneElement = originalElement.clone();
cloneElement.attr({'name': name, 'value': value});
$(cloneElement).appendTo(form);
}
return form;
},
ajaxFileUpload: function (s) {
// TODO introduce global settings, allowing the client to modify them for all requests, not only timeout
s = jQuery.extend({}, jQuery.ajaxSettings, s);
var id = new Date().getTime()
var form = jQuery.createUploadForm(id, s.fileElementId);
if (s.data) form = jQuery.addOtherRequestsToForm(form, s.data);
var io = jQuery.createUploadIframe(id, s.secureuri);
var frameId = 'jUploadFrame' + id;
var formId = 'jUploadForm' + id;
// Watch for a new set of requests
if (s.global && !jQuery.active++) {
jQuery.event.trigger("ajaxStart");
}
var requestDone = false;
// Create the request object
var xml = {}
if (s.global)
jQuery.event.trigger("ajaxSend", [xml, s]);
// Wait for a response to come back
var uploadCallback = function (isTimeout) {
var io = document.getElementById(frameId);
try {
if (io.contentWindow) {
xml.responseText = io.contentWindow.document.body ? io.contentWindow.document.body.innerHTML : null;
xml.responseXML = io.contentWindow.document.XMLDocument ? io.contentWindow.document.XMLDocument : io.contentWindow.document;
} else if (io.contentDocument) {
xml.responseText = io.contentDocument.document.body ? io.contentDocument.document.body.innerHTML : null;
xml.responseXML = io.contentDocument.document.XMLDocument ? io.contentDocument.document.XMLDocument : io.contentDocument.document;
}
} catch (e) {
jQuery.handleError(s, xml, null, e);
}
if (xml || isTimeout == "timeout") {
requestDone = true;
var status;
try {
status = isTimeout != "timeout" ? "success" : "error";
// 确保请求成功或未修改
if (status != "error") {
// 处理数据(无论回调如何,都通过httpData运行xml
var data = jQuery.uploadHttpData(xml, s.dataType);
// 如果指定了本地回调,则将其触发并传递数据
if (s.success)
s.success(data, status);
// 触发全局回调
if (s.global)
jQuery.event.trigger("ajaxSuccess", [xml, s]);
} else
jQuery.handleError(s, xml, status);
} catch (e) {
status = "error";
jQuery.handleError(s, xml, status, e);
}
// The request was completed
if (s.global)
jQuery.event.trigger("ajaxComplete", [xml, s]);
// Handle the global AJAX counter
if (s.global && !--jQuery.active)
jQuery.event.trigger("ajaxStop");
// Process result
if (s.complete)
s.complete(xml, status);
jQuery(io).unbind()
setTimeout(function () {
try {
$(io).remove();
$(form).remove();
} catch (e) {
jQuery.handleError(s, xml, null, e);
}
}, 100)
xml = null
}
}
// Timeout checker
if (s.timeout > 0) {
setTimeout(function () {
// Check to see if the request is still happening
if (!requestDone) uploadCallback("timeout");
}, s.timeout);
}
try {
// var io = $('#' + frameId);
var form = $('#' + formId);
$(form).attr('action', s.url);
$(form).attr('method', 'POST');
$(form).attr('target', frameId);
if (form.encoding) {
form.encoding = 'multipart/form-data';
} else {
form.enctype = 'multipart/form-data';
}
$(form).submit();
} catch (e) {
jQuery.handleError(s, xml, null, e);
}
if (window.attachEvent) {
document.getElementById(frameId).attachEvent('onload', uploadCallback);
} else {
document.getElementById(frameId).addEventListener('load', uploadCallback, false);
}
return {
abort: function () {
}
};
},
//重点,这里就是对后台的返回数据进行处理,返回的data会被传入回调函数success(data,status)中
uploadHttpData: function (r, type) {
var data = !type;
data = type == "xml" || data ? r.responseXML : r.responseText;
// console.log("type--"+type);
// If the type is "script", eval it in global context
if (type == "script")
jQuery.globalEval(data);
// Get the JavaScript object, if JSON is used.
if (type == "json") {
//将从后台传过来的json格式的字符串转换成json返回,这是我改的地方
// data = eval("(" + data + ")");//这种转换兼容所有浏览器,但不安全,会执行json里面的表达式
data = JSON.parse(data); //这种方式安全,但不兼容IE7
}
// evaluate scripts within html
if (type == "html")
jQuery("<div>").html(data).evalScripts();
//alert($('param', data).each(function(){alert($(this).attr('value'));}));
console.log("data13:" + data);
return data;
}
})
js部分写完了,那么就到了后台servlet了
注意:在下面将是否上传成功的信息写回客户端是以json格式字符写回去,不是向客户端写回一个对象,那么就要用到相应的将对象转变为json的jar包,里面有个ObjectMapper类
如下:
servlet部分代码:
@WebServlet(urlPatterns="/upfile")
@MultipartConfig
public class FileUpUtil extends HttpServlet {
private static final long serialVersionUID = 4728407898261233142L;
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
File file=new File("D:\\upFile");
if(!file.exists()){//如果文件夹不存在
file.mkdir();//创建文件夹
}
String path = "D:\\upFile";//该文件夹用于保存你的文件
Collection<Part> names = req.getParts();//得到文件对象
for (Part part : names) {
if(part.getContentType() != null) {
String header = part.getHeader("Content-Disposition");//获得请求头中Content-Disposition的内容,这里面包含文件的名字
System.out.println(header);
String fileName = getFileName(header);//得到文件名,自己写的拆分字符串方法
System.out.println(fileName);
String filePath = path + File.separator + fileName;
ReqMessage data = new ReqMessage(true, "上传到服务器成功");//实例化返回消息
try {
part.write(filePath);//向目标位置写入真实文件
part.delete();//删除临时文件
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
data.setStatus(false);
data.setInformation("系统繁忙,请稍后重试!");
}
ObjectMapper om = new ObjectMapper();
String json = om.writeValueAsString(data);//将对象转变成json格式的字符串
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");//设置返回后的格式
PrintWriter out = resp.getWriter();
out.println(json);//将信息以json格式返回
}
}
}
//拆分字符串,获得文件名的方法
private String getFileName(String header) {
String[] strs = header.split(";");
String[] tmpArrs = strs[2].split("=");
String fileName = tmpArrs[1];
return fileName.substring(1, fileName.length() - 1);
}
}
代码中用到的一些自己写的bean文件,其实就一个ReqMessage,用于装返回信息的
代码如下:
public class ReqMessage implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2954844625138246393L;
private boolean status;//保存状态
private String information;//保存具体信息
public ReqMessage() {
super();
}
public ReqMessage(boolean status, String information) {
super();
this.status = status;
this.information = information;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
public String getInformation() {
return information;
}
public void setInformation(String information) {
this.information = information;
}
@Override
public String toString() {
return "ReqMessage [status=" + status + ", information=" + information + "]";
}
}
那么写完了后,点击上传后会弹出来返回的这个信息
不是图片的其他文件上传的效果:
图片上传的效果:
上传成功后的效果: