首先用EasyUI做界面:
<div id="loading2">
<div class="inputdiv" >
<img class="prtspan span_1" src="images/loading.gif"/>
<h3 class="prtspan span_1" >war包正在部署,请稍候......</h3>
</div>
</div>
<div id="loading1" style="display:none;">
<div id="loading" class="easyui-progressbar" style="width:700px;"></div>
</div>
前端主要的js代码:
//定时器:文件上传是否完成了
var _finished = false;
function update_file_percent(){
if(_finished) return;
$.get("deploy/searchWar.action",{}
,function(data,textStatus){
if(data=="100" || data==100){
$('#loading').progressbar('setValue',0);
$('#loading1').css("display","none");
$('#loading2').window('open');
return;
}
$('#loading').progressbar('setValue', parseInt(data)); //返回的data包含换行符,必须要转成数字,否则进度条出不来颜色
setTimeout("update_file_percent()", 1000);
});
}
//部署应用程序
function list_to_deploy_app(){
$("#btnAddWar").click(function(){
_finished = false;
$("btnAddWar").attr("disabled","true");
$('#loading').progressbar('setValue', 0);
$('#loading1').css("display","block");
$.post("deploy/addWar.action",{type:"first"},function(data,textStatus){
setTimeout("update_file_percent()", 1000);
$('#addWar').form('submit',
{
url:"deploy/addWar.action",
onSubmit: function(){
$("#hip").val(ip);
$("#hport").val(port);
},
success:function(data){
_finished = true;
$('#loading2').window('close');
$('#loading1').css("display","none");
$('#loading').progressbar('setValue',0);
var m_obj = JSON.parse(data);
$("btnAddWar").attr("disabled","false");
if(m_obj && m_obj.success == true){
messagebox_tip('war包' + $("#incontext").val() + '部署成功!');
}else{
messagebox_tip('war包' + $("#incontext").val() + '部署失败!\n失败原因是:'+m_obj.message);
}
}
}
);//form submit
});
}
);
}
后端java代码:
需要自己写程序调用common-fileupload来处理上传的文件,但在代码调用upload.parseRequest(request)来处理时,返回了空的items
我在网上看了很多帖子,最终总结出一个相对来说比较简单的方法:
自已新增一个servlet Filter,并且把它的filter次序放到struts2的filter次序之前
将如下内容放在web.xml文件中其他filter的前面:
<!-- file filter -->
<filter>
<filter-name>AuthFilter</filter-name>
<filter-class>com.southgis.scout.hub.action.deploy.AuthFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AuthFilter</filter-name>
<url-pattern>/deploy/addWar.action</url-pattern>
</filter-mapping>
新建的Filter的代码如下:
package com.southgis.scout.hub.action.deploy;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.dispatcher.StrutsRequestWrapper;
public class AuthFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter(new StrutsRequestWrapper((HttpServletRequest) request), response);
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}
这里先用StrutsRequestWrapper来给他wrapper一次,这样在经过struts2的filter的时候就不会有问题了。为啥呢?可以自己看看这个类
org.apache.struts2.dispatcher.Dispatcher里面的wrapRequest方法,有这么个判断:
if (request instanceof StrutsRequestWrapper) {
return request;
}
非常给力的处理方式。
package com.southgis.scout.hub.action.deploy;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.fileupload.ProgressListener;
public class UploadListener implements ProgressListener {
private HttpSession session1;
public UploadListener(HttpServletRequest request) {
session1=request.getSession(false);
}
public void update(long bytesRead, long contentLength, int items) {
int percent = (int) (100 * (double) bytesRead / (double) contentLength);
session1.setAttribute("read",String.valueOf(percent));
}
}
处理文件上传核心代码DeployAction.java:
package com.southgis.scout.hub.action.deploy;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
import com.alibaba.fastjson.JSONObject;
import com.southgis.scout.core.action.BaseAction;
import com.southgis.scout.core.util.HttpUtil;
@Namespace("/deploy")
public class DeployAction extends BaseAction {
private static final long serialVersionUID = 1L;
private void executePost() throws ServletException, IOException {
String type=request.getParameter("type");
if(type!=null){
//第一次初始化session
HttpSession session = request.getSession(false);
if(session!=null)
{
session.invalidate();
}
session = request.getSession(true);
return;
}
String filePath="";
// 监听器
UploadListener listener = new UploadListener(request);
// Apache 上传工具
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置 listener
upload.setProgressListener(listener);
Map<String, String> map = new HashMap<String, String>();
try {
List itemList = upload.parseRequest(request);
for (Iterator it = itemList.iterator(); it.hasNext();) {
FileItem item = (FileItem) it.next();
if (!item.isFormField()) {
// 获取文件输出目录
String nowpath; //当前tomcat的bin目录的路径 如 D:\java\software\apache-tomcat-6.0.14\bin
String tempdir;
nowpath=System.getProperty("user.dir");
tempdir=nowpath.replace("bin", "wars"); //把bin 文件夹变到 webapps文件里面
//如果不存在tempdir则新建目录
File myPath = new File(tempdir);
if (!myPath.exists()) {
myPath.mkdir();
}
//tempdir="F:/wars";测试用
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
// 统一 Linux 与 windows 的路径分隔符
String fileName =formatter.format(new Date()) + item.getName().replace("/", "\\");
filePath=tempdir+"/"+fileName;
File saved = new File(filePath);
saved.getParentFile().mkdirs();
item.write(saved);
}
else{
map.put(item.getFieldName(),item.getString());
}
}
} catch (Exception e) {
outJsonResult(new JSONObject());
}
String url = "http://" + map.get("ip") + ":" + map.get("port") + "/plug/deploy/deploywar";
String a="true";
if(map.get("update")==null){
a="false";
}
map.put("update", a);
String result = HttpUtil.postFile(url, "attach", filePath, map);
JSONObject jsonObj = JSONObject.parseObject(result);
outJsonResult(jsonObj);
}
@Action("addWar")
public void addWar() throws Exception {
executePost();
}
@Action("searchWar")
public void searchWar() throws Exception {
response.setHeader("Cache-Control", "no-store");
response.setHeader("Pragrma", "no-cache");
response.setDateHeader("Expires", 0);response.setContentType("text/html;charset=UTF-8");
//如果不这样就会出现firefox 的jQuery.get返回object xmldocument的问题,或者你在jQuery.get中设置dataType为text
HttpSession session = request.getSession(false);
String value=(String )session.getAttribute("read");
if (value != null) {
response.getWriter().println(value);
}
else{
response.getWriter().println("0");
}
}
}
最后注意:
debug的时候可以用Fiddler抓包工具查看从后台get来的进度信息,但是如果你想体验进度条,则必须要关闭Fiddler。
否则就会出现浏览器上传文件,左下角提示上传百分之多少,然后完成,然后进度条才逐渐显示百分之几。这个问题困扰了我很久。一开始我还冤枉是Apache的commons-fileupload有问题:进度条信息只是针对服务器端保存文件的进度,而不是浏览器上传文件的进度。
其实是我错了,Apache的commons-fileupload确实能针对浏览器上传文件提供进度信息。看来Apache的东西确实牛逼。