今天写一下最近用webuploader插件遇到的困难,关于它的使用百度上有很多例子,大家自行百度,推荐看官方API。
这款上传插件的优点在于支持html5和flash两种上传方式,默认是html5否则用flash,例如ie10、ie11和火狐等用html5上传,ie6-ie9用flash上传。
1.先附上前端代码:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String path=request.getContextPath();
%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="stylesheet" type="text/css" href="<%=path%>/js/uploader/webuploader.css">
<script type="text/javascript" src="<%=path%>/js/jquery-1.8.2.min.js" ></script>
<script type="text/javascript" src="<%=path%>/js/uploader/webuploader.js"></script>
<title>WebUploader</title>
<script>
var PATH = '<%=path%>';
$(function(){
//初始化上传插件
var uploader = WebUploader.create({
auto: false,// 选完文件后,是否自动上传。
swf: PATH + '/js/uploader/Uploader.swf',// swf文件路径
server: PATH + '/login', // 文件接收服务端。
pick: {
"id":'#picker', //绑定上传标签,可以class名绑定多个。
"multiple":false //禁止多选。
}
});
// 当有文件被添加进队列的时候
uploader.on( 'fileQueued', function( file ) {
$("#thelist").append( '<div id="' + file.id + '" class="item">' +
'<h4 class="info">' + file.name + '</h4>' +
'<p class="state">等待上传...</p>' +
'</div>' );
});
// 文件上传过程中创建进度条实时显示。
uploader.on( 'uploadProgress', function( file, percentage ) {
var $li = $( '#'+file.id ),
$percent = $li.find('#progress .progress-bar');
// 避免重复创建
if ( !$percent.length ) {
$percent = $('<div id="progress" class="progress progress-striped active">' +
'<div class="progress-bar" role="progressbar" style="height:20px;background-color:blue;width: 0%">' +
'</div>' +
'</div>').appendTo( $li ).find('.progress-bar');
}
$li.find('p.state').text('上传中');
$percent.css( 'width', percentage * 100 + '%' );
});
uploader.on( 'uploadSuccess', function( file ) {
$( '#'+file.id ).find('p.state').text('已上传');
});
uploader.on( 'uploadError', function( file ) {
$( '#'+file.id ).find('p.state').text('上传出错');
});
uploader.on( 'uploadComplete', function( file ) {
$( '#'+file.id ).find('.progress').fadeOut();
});
//上传按钮点击事件
$("#ctlBtn").on( 'click', function() {
uploader.upload();
});
});
</script>
</head>
<body>
<div id="uploader" class="wu-example">
<!--用来存放文件信息-->
<div id="thelist" class="uploader-list"></div>
<div class="btns">
<div id="picker">选择文件</div>
<button id="ctlBtn" class="btn btn-default">开始上传</button>
</div>
</div>
</body>
</html>
2.后端上传文件的java代码如下:
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public UploadServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
@SuppressWarnings("unchecked")
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//文件存放的目录
File tempDirPath =new File(request.getSession().getServletContext().getRealPath("/")+"\\upload\\");
if(!tempDirPath.exists()){
tempDirPath.mkdirs();
}
//创建磁盘文件工厂
DiskFileItemFactory fac = new DiskFileItemFactory();
//创建servlet文件上传组件
ServletFileUpload upload = new ServletFileUpload(fac);
//文件列表
List fileList = null;
//解析request从而得到前台传过来的文件
try {
fileList = upload.parseRequest(request);
} catch (FileUploadException ex) {
ex.printStackTrace();
return;
}
//保存后的文件名
String imageName = null;
//便利从前台得到的文件列表
Iterator<FileItem> it = fileList.iterator();
while(it.hasNext()){
FileItem item = it.next();
//如果不是普通表单域,当做文件域来处理
if(!item.isFormField()){
//imageName = new Date().getTime()+Math.random()*10000+item.getName();
imageName = item.getName();
BufferedInputStream in = new BufferedInputStream(item.getInputStream());
BufferedOutputStream out = new BufferedOutputStream(
new FileOutputStream(new File(tempDirPath+"\\"+imageName)));
Streams.copy(in, out, true);
}
}
//将文件名转换成json输出
Map<String,Object> param = new HashMap<String,Object>();
param.put("name", imageName);
String jsonString = JSON.toJSONString(param, true);
PrintWriter out = null;
try {
out = encodehead(request, response);
} catch (IOException e) {
e.printStackTrace();
}
//这个地方不能少,否则前台得不到上传的结果
out.write(jsonString);
out.close();
}
/**
* Ajax辅助方法 获取 PrintWriter
* @return
* @throws IOException
* @throws IOException
* request.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=utf-8");
*/
private PrintWriter +encodehead(HttpServletRequest request,HttpServletResponse response) throws IOException{
request.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=utf-8");
return response.getWriter();
}
}
3.注意事项:
该上传插件不处理前端ui,所以前端留给开发者很大发挥空间,这里提示用户在看官方文档时如果实现它的例子会发现进度条不显示,这就需要开发者写进度条的css,其实进度条已经在页面上了,只是它的height没有即它没有高度,看懂上边的前端代码可以看出我已经简单的加了高度和背景色,具体想要什么样式,就看各自发挥了。修改进度条css的地方为:
// 避免重复创建
if ( !$percent.length ) {
$percent = $('<div id="progress" class="progress progress-striped active">'+
'<div class="progress-bar" role="progressbar" style="height:20px;background-color:blue;width: 0%">' +'</div>' + '</div>').appendTo( $li ).find('.progress-bar');
}
4.使用中遇到的困难:
(1)一定要注意上传成功java返回的要是json。如果不是json,用html5上传的浏览器不会报错,可以上传成功,但如果是用flash上传的浏览就会报错,导致结果为文件能够上传,但不能转跳到成功的方法中,所以切记用flash上传的话一定要返回json格式的数据,可以看见上边的代码我特意将文件名放到map中在转为json输出到前端的。
(2)上传中文名文件乱码。乱码原因我没找到,页面编码什么的不用考虑了,我都排除了,如果有知道原因的希望留言告知。这里我的处理方式请看(3),(3)中处理了乱码并给文件重命名。
(3)上传文件重命名。虽然文件重命名可以再java中处理,但如果你有很多上传的地方,每个上传地方的重命名方式不一样,而java用的是一个,这时候在插件中重命名就有用了。首先在插件初始化时加入属性 formData: {file_name: ‘file_name’ },代码如下:
var uploader = WebUploader.create({
auto: true,// 选完文件后,是否自动上传。
swf: PATH + '/common/webuploader/Uploader.swf',
server: PATH+'/fileAction.do?method=doUploadFile',
formData: {
file_name: 'file_name'
},
pick: {
"id":'#uploadDiv',
"multiple":false //禁止多选。
}
});
然后加入如下方法:
uploader.on( 'uploadBeforeSend', function( block,data ) {
data.file_name = encodeURI(block.file.name.substring(0,block.file.name.indexOf("."))+"-2017"++block.file.name.substring(block.file.name.indexOf("."),block.file.name.length));
});
可以看到在上传前为文件重命名加了“-2017”,顺便为文件名用encodeURI编码,那么后端就用如下代码接收:
String fileName=URLDecoder.decode(upload.parseRequest(request).getParameter("file_name"),"UTF-8");
upload是上传文件的架包中的类,这个用法具体百度。
这时一般前端还要获取修改后的文件名,可能你会以为file.name不就是吗,它是修改前的文件名,其实可以在(1)中将修改后的文件名放在json里输出到前端,这是前端接收的代码如下:
uploader.on( 'uploadSuccess', function( file , response ) {
alert(response.file_name);
});
因为后端在(1)中放入map中时key值为file_name,所以前端用response.file_name取值。(response是后端返回的json,建议大家循环看一下其中除了咱添加的数据,默认还添加了什么。)
以上便是我在用webuploader时处理文件名乱码和文件重命名的方法。