前端:
直接通过图片的URL加载图片
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/afquery.js"></script>
<style>
.main{
}
.main input{
margin: 20px;
}
.main .upload{
background-color: cornflowerblue;
color: #fff;
border: 1px solid #ccc;
border-radius: 1px;
padding: 8px 18px;
}
</style>
</head>
<body>
<div class="main">
<input type="file" class="filebutton" style="display: none" /><br />
<button class="upload" οnclick="selectFile()">选择文件上传</button>
<div>
<img class="imagebox" src="" style="width: 300px;" />
</div>
</div>
</body>
<script>
//初始化
var up = new AfUploader();
up.setButton('.filebutton'); // 设置file input控件
up.setUploadUrl('FileUploadService'); // 设置服务URL
up.setLogEnabled( false );
// 事件处理 'start' 'progress' 'complete' 'error' 'abort'
up.processEvent = function(event)
{
if(event == 'progress')
{
Af.log("进度: " + this.progress);
}
else if(event == 'complete')
{
Af.log("完成上传");
Af.log(this.response);
var jresp = JSON.parse (this.response);
var url = jresp.data.url;
$('.imagebox').attr('src', url);
}
};
//是否允许上传
up.beforeUpload = function()
{
if(this.file.size > 10*1000000)
{
alert("文件太大!");
return false;
}
return true;
};
function selectFile()
{
up.openFileDialog();
}
</script>
</html>
这里用到了封装好的自定义文件上传工具类(afquery.js):
网址:邵发老师
/*
* 上传工具类
*/
function AfUploader()
{
this.fileButton = null; // 原生DOM
this.file = null; // 要上传的文件
this.uploadUrl = null;
this.status = 0; // 0, 1, 100, -1(失败), -2(canceled)
this.progress = 0; // 0-100
this.response = "{}"; // 上传完毕后服务器的返回值, 一般应该是一个JSON字符串
this.enableLog = true; // 是否显示内部打印
// 输入参数可以是:Selector / jQuery对象 / 原生DOM
this.setButton = function(fileButton)
{
// 如果输入参数是 Selector
if(fileButton.constructor == String) fileButton = $(fileButton);
// 如果输入参数是jQuery对象, 则转成DOM
if(fileButton.constructor == jQuery)
{
if(fileButton.length==0) throw ("你的jQuery选择器写错了!请检查选择器!");
fileButton = fileButton[0];
}
// 先看原来有没有绑定, 如果已经绑定了一个uploader,则返回原有对象
if(fileButton.uploader != null) return fileButton.uploader;
// 创建新的uploader
this.fileButton = fileButton;
// 把上下文存放到DOM元素里
this.fileButton.uploader = this;
// 添加回调,确保只添加一次
// this.fileButton.removeEventListener("change", this.onFileChanged);
// this.fileButton.addEventListener("change", this.onFileChanged);
this.fileButton.addEventListener("change", function(){
var ctx = this.uploader;
var fileButton = this;
if(fileButton.files.length == 0) return;
var file = fileButton.files[0];
ctx.log("select file: " + file.name);
fileButton.value = ''; // 清空选择
ctx.setFile(file);
ctx.startUpload( );
});
return this;
};
this.setUploadUrl = function(url)
{
this.uploadUrl = url;
return this;
};
// 事件处理 : 'start' 'progress' 'complete' 'error' 'abort'
this.processEvent = function( event )
{
};
// 是否接受上传, true:可以上传; false:不能上传
this.beforeUpload = function()
{
return true;
};
this.setLogEnabled = function( enabled)
{
this.enableLog = enabled;
return this;
};
// 设置文件 (并不立即启动)
this.setFile = function(file)
{
this.file = file;
return this;
};
// 打开文件对话框,让用户选择文件
this.openFileDialog = function()
{
if(this.fileButton == null) throw ("尚未初始化file button! 请调用 setButton() 进行设置!");
$(this.fileButton).click();
};
// 外部可以直接送进来一个 File 对象
this.startUpload = function( )
{
if(this.uploadUrl == null) throw ("尚未设置uploadUrl,无法上传! 请调用 setUploadUrl()进行设置!");
if(this.file == null) throw ("尚未设置file! 请调用openFileDialog()打开文件选择对话框!或者调用setFile()传一个File对象!");
var file = this.file;
// 上传测试: 是否允许上传
if( ! this.beforeUpload())
{
this.log("不满足上传条件 ! " + file.name);
return;
}
this.log("开始上传: " + file.name);
var formData = new FormData();
formData.append('file', file); // 'file' 为HTTP Post里的字段名, file 对浏览器里的File对象
var formRequest = new XMLHttpRequest();
formRequest.ctx = this;
formRequest.upload.ctx = this;
formRequest.upload.addEventListener("progress", this.evt_upload_progress, false);
formRequest.addEventListener("load", this.evt_upload_complete, false);
formRequest.addEventListener("error", this.evt_upload_failed, false);
formRequest.addEventListener("abort", this.evt_upload_cancel, false);
this.processEvent('start');
formRequest.open("POST", this.uploadUrl );
formRequest.send(formData);
this.formRequest = formRequest; /* 保存这个上传者对象, 用于调用其abort()函数 */
this.status = 1;
return this;
};
// 取消上传
this.cancelUpload = function()
{
if(this.formRequest != null)
{
try{
this.formRequest.abort();
this.formRequest = null;
this.status = -2;
}catch(err)
{
Af.log("取消上传时出错 :" + err);
}
}
};
this.log = function(msg)
{
if(!this.enableLog) return;
try { console.log(msg); } catch (err) {}
};
//////////////////////////////
this.evt_upload_progress = function (evt)
{
var ctx = this.ctx;
if (evt.lengthComputable)
{
ctx.progress = Math.round(evt.loaded * 100 / evt.total);
ctx.log ("上传进度: " + ctx.progress);
ctx.processEvent('progress');
}
};
this.evt_upload_complete = function (evt)
{
var ctx = this.ctx;
if(evt.loaded == 0)
{
ctx.status = -1;
ctx.log ("上传失败!" + ctx.file.name);
ctx.processEvent('error');
}
else
{
ctx.status = 100;
ctx.response = evt.target.responseText;
ctx.log (ctx.response);
ctx.processEvent('complete');
}
};
this.evt_upload_failed = function (evt)
{
var ctx = this.ctx;
ctx.status = -1;
ctx.log ("上传出错");
ctx.processEvent('error');
};
this.evt_upload_cancel = function (evt)
{
var ctx = this.ctx;
ctx.status = -2;
ctx.log( "上传中止!");
ctx.processEvent('abort');
};
}
后端:
package my;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;
import org.json.JSONObject;
@WebServlet("/FileUploadService")
public class FileUploadService extends HttpServlet
{
// 文件上传的临时目录
File tmpDir ;
@Override
public void init() throws ServletException
{
File webroot = new File(getServletContext().getRealPath("/"));
tmpDir = new File(webroot, "upload");
tmpDir.mkdirs(); // 上传进来的文件存放在 WebRoot/upload/ 下
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
JSONObject jresp = new JSONObject();
try
{
Object data = doUpload(request, response);
jresp.put("error", 0);
jresp.put("reason", "OK");
if(data != null)
jresp.put("data", data);
} catch (Exception e)
{
jresp.put("error", -1);
jresp.put("reason", e.getMessage());
}
response.setCharacterEncoding("UTF-8");
response.setContentType("text/plain");
PrintWriter out = response.getWriter();
out.write(jresp.toString(2));
out.close();
}
private Object doUpload(HttpServletRequest request,
HttpServletResponse response) throws Exception
{
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if(!isMultipart)
throw new Exception("请求编码必须为: multipart/form-data !");
request.setCharacterEncoding("utf-8");
ServletFileUpload upload = new ServletFileUpload();
AfFileUploadInfo info = new AfFileUploadInfo();
FileItemIterator iter = upload.getItemIterator(request);
while(iter.hasNext())
{
//表单域
FileItemStream item = iter.next();
String fieldName = item.getFieldName();
InputStream fieldStream = item.openStream();
if(item.isFormField())
{
// 普通表单域: 直接读取值
String fieldValue = Streams.asString(fieldStream, "utf-8");
printLog("表单域:" + fieldName + "=" + fieldValue);
}
else
{
// 生成唯一的文件名
info.realName = item.getName(); // 原始文件名
info.suffix = fileSuffix(info.realName); // 后缀
info.tmpFileName = createTmpFileName(info.suffix); // 服务器临时文件名
info.tmpFile = new File(tmpDir, info.tmpFileName);
info.fileSize = 0; // 文件大小
printLog("文件上传开始:" + info.realName + " >> " + info.tmpFile);
// 从FieldStream读取数据, 保存到目标文件
info.tmpFile.getParentFile().mkdirs();
FileOutputStream fileStream = new FileOutputStream(info.tmpFile);
try{
// 从请求里读取文件数据,保存到本地文件
info.fileSize = copy(fieldStream, fileStream);
}finally{
try{ fileStream.close();}catch(Exception e){}
try{ fieldStream.close();}catch(Exception e){}
}
printLog("文件上传完成:" + info.realName + ", 大小: " + info.fileSize);
}
}
// storePath: /upload/20180817-225649-948CC60AFD374333924DF2F3A049417D.jpg
String storePath = "/upload/" + info.tmpFileName;
// contextPath: /demo1601
String url = getServletContext().getContextPath() + storePath;
JSONObject result = new JSONObject();
result.put("storePath", storePath);
result.put("url", url);
return result;
}
private long copy(InputStream in, OutputStream out) throws Exception
{
long count = 0;
byte[] buf = new byte[8192];
while (true)
{
int n = in.read(buf);
if (n < 0)
break;
if (n == 0)
continue;
out.write(buf, 0, n);
count += n;
}
return count;
}
//////////////////////////////////////////////////
private void printLog(String message)
{
System.out.println(message);
}
// 生成一个唯一的ID
private String createUUID ()
{
String s = UUID.randomUUID().toString();
String s2 = s.substring(0,8)+s.substring(9,13)+s.substring(14,18)+s.substring(19,23)+s.substring(24);
return s2.toUpperCase();
}
// 得到一个保证不重复的临时文件名
private String createTmpFileName(String suffix)
{
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss");
String datestr = sdf.format(new Date());
String name = datestr + "-" + createUUID() + "." + suffix;
return name;
}
// 得到文件的后缀名
public String fileSuffix(String fileName)
{
int p = fileName.lastIndexOf('.');
if(p >= 0)
{
return fileName.substring(p+1).toLowerCase();
}
return "";
}
}
package my;
import java.io.File;
public class AfFileUploadInfo
{
public String realName; //原始文件名
public String suffix; //后缀
public String tmpFileName; //服务器临时文件名
public File tmpFile;
public long fileSize; //文件大小
}