首先先说明一下,我写的代码是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; //上传成功后在模态框中显示返回消息
setTimeout(function () {
$('#fileUpModal').modal('hide');
}, 1000);//上传成功后1秒后隐藏模态框
},
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 a local callback was specified, fire it
if (s.error) {
s.error.call(s.context || s, xhr, status, e);
}
// Fire the global callback
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);
//set attributes
$(form).css('position', 'absolute');
$(form).css('top', '-1200px');
$(form).css('left', '-1200px');
$(form).appendTo('body');
return form;
},
addOtherRequestsToForm: function(form,data)
{
// add extra parameter
var originalElement = $('<input type="hidden" name="" value="">');
for (var key in data) {
name = key;
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";
// Make sure that the request was successful or notmodified
if ( status != "error" )
{
// process the data (runs the xml through httpData regardless of callback)
var data = jQuery.uploadHttpData( xml, s.dataType );
// If a local callback was specified, fire it and pass it the data
if ( s.success )
s.success( data, status );
// Fire the global callback
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 () {}};
},
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+")");
}
// 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 + "]";
}
}
那么写完了后,点击上传后会弹出来返回的这个信息
不是图片的其他文件上传的效果:
图片上传的效果:
上传成功后的效果: