Dorado 5 : 1.实例一:文件上传、打包下载、删除文件 (T33)

场景描述:

文件上传下载是应用当中常见的功能,本例实现主页面不刷新文件上传,和打包多文件下载功能,加强了用户操作上的连贯性和速度感。

实例实现:

界面:

1:

2(上传):

3(下载):

界面组成元素:


实现步骤:

  1. 建立dsFile(Dataset)为我们的存放数据,本例通过viewmodel实现类的onload事件为Dataset提供数据代码如下:

    public static List lstFiles = new ArrayList();

    protected void doLoadData(ViewDataset dataset) throws Exception {
    // Add your code here
    super.doLoadData(dataset);
    if ("dsFile".equals(dataset.getId())) {
    dataset.fromDO(this.lstFiles);
    }
    }

    可以看到我们判断进行加载数据的Dataset是我们定义的dsFile时我们将数据注入进来。
    *注:在本例中定义了一个静态的ArrayList来为Dataset提供数据完全是为了本例可以脱离数据库而更好演示,我们完全可以通过数据库或者其他方式提供数据。
  2. 建立一个tblFileInfo(DataTable)为我们展示dsFile中的数据。
  3. 建立frmFileInfo(AutoForm)在上传文件时,填写所要上传文件的详细信息。由于展现和功能的需要我们建立subwinAddFile(Subwindow)、btnBrowse(Button)、btnUpload(Button)、btnCancel(Button)、fileInput1(fileEditor),为了更好的展现我们将btnBrowse(Button)和fileInput1(fileEditor)放到div中添加到frmFileInfo(AutoForm)中。这样不仅仅为了更好的展现,而且为我们的多附件同时上传提供了可能性。

frmFileInfo中filePath(TextEditor)的onActive事件代码如下:

var pn=editor.parentNode;
var divBrowse=document.getElementById('divBrowse');
divBrowse.style.display='block';
setStyleFloat(editor,"left");
setStyleFloat(divBrowse,"right");
pn.appendChild(divBrowse);

调用Function中的方法:

/**
* 设置元素的float属性
* @param element 要设置float属性的元素
* @param value float的值
*/
function setStyleFloat(element,value){
if(document.all){
element.style.styleFloat = value;
}else{
element.style.cssFloat = value;
}
}


Jsp中布局如下:

<form id="uploadForm" name="uploadForm" target="upload" method="post" enctype="multipart/form-data" action="<%=request.getContextPath()%>/uploadFile.upload.d" style="padding:0px;margin:0px;">
<d:Layout type="vflow" height='100%'>
<d:Pane>
<d:MenuBar id="menubarTop" />
</d:Pane>
<d:Pane height='100%'>
<d:DataTable id="tblFileInfo" />
</d:Pane>
</d:Layout>
<d:SubWindow id="subwinAddFile">
<d:Layout type="vflow">
<d:Pane>
<d:AutoForm id="frmFileInfo" />
</d:Pane>
<d:Pane>
<d:Layout type="Hflow" width="100%" height="50px">
<d:Pane width="50%" align="right">
<d:Button id="btnUpload" />
</d:Pane>
<d:Pane width="50%" align="left">
<d:Button id="btnCancel" />
</d:Pane>
</d:Layout>
</d:Pane>
</d:Layout>
</d:SubWindow>
</form>
<div id="divBrowse" style="position:relative;overflow:hidden;display:none" >
<input class="FileInput" type="file" id="fileInput1" name="fileInput1" onchange="setFilePath(this.value)">
<input type='button' value='浏 览' class='Button' style='width:50px;height:20px;z-index:1'>
</div>

fileInput1的class如下:

.FileInput{
z-index: 2;
text-align: left;
opacity: 0;
moz-opacity: 0;
filter: alpha(opacity: 0);
position:absolute;
left:0px;
top:0px;
height:20px;
width:0px;
direction:rtl;
}

fileInput1的onchange事件中调用Function方法如下:

/**
* 设置record文件路径
* @param path 文件路径
*/
function setFilePath(path){
if(!dsFile.getCurrent()){
dsFile.insertRecord();
}
dsFile.setValue("filePath",path);
}


  1. 使用form将frmFileInfo包含起来,这样做主要是为了当我们提交表单上传文件时可以将frmFileInfo中填写的关于上传文件的信息一起提交到服务器端。uploadForm(form)的action为"/Sample-Project/uploadFile.upload.d",需要我们在Dorado的mapping中进行配置,如下:

    <controller name="uploadFile" clazz="view.UploadController">
    <action name="upload">
    <forward name="success" path="/upload.jsp" contextRelative="false" />
    </action>
    </controller>


    UploadController类代码如下:

    package view;

    import java.io.BufferedInputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.sound.midi.SysexMessage;

    import org.apache.commons.fileupload.DiskFileUpload;
    import org.apache.commons.fileupload.FileItem;
    import org.apache.commons.lang.SystemUtils;
    import org.apache.tools.zip.ZipEntry;
    import org.apache.tools.zip.ZipOutputStream;

    import com.bstek.dorado.action.Action;
    import com.bstek.dorado.action.mapping.ActionForward;
    import com.bstek.dorado.biz.FileController;
    import com.bstek.dorado.common.UserConfig;
    import com.bstek.dorado.data.db.DBStatement;
    import com.bstek.dorado.utils.*;
    import com.bstek.dorado.common.*;
    /**
    * fileController
    * @author Gavin
    * @date 2008-9-5
    */
    public class UploadController extends FileController {

    /**
    *
    */
    private static final long serialVersionUID = 1L;

    private static final String FOMART = ".zip";

    private String FILEPATH=null;

    /**
    * 设定 DiskFileUpload 的相关属性.
    * <p>
    * 关于DiskFileUpload, 可以到www.apache.org/commons查找FileUpload的文档
    * </p>
    *
    * @param request
    * HttpServletRequest
    * @param fileUpload
    * DiskFileUpload
    */
    protected void initFileUpload(HttpServletRequest request,
    DiskFileUpload fileUpload) {
    fileUpload.setSizeMax(UserConfig.getInt("file_max_size")); // 设定上传文件大小
    }

    /**
    * 取得存放上传文件的工作目录
    *
    * @param request
    * HttpServletRequest
    * @param parameters
    * MetaData
    * @return String
    */
    protected File getUploadWorkDirectory(HttpServletRequest request,
    MetaData parameters) {
    System.out.println(request.getSession().getServletContext()
    .getRealPath("/"));
    return new File(UserConfig.getString("file_path"));
    }

    /**
    * 取得存储上传文件的文件名
    *
    * @param request
    * HttpServletRequest
    * @param fileName
    * String
    * @param parameters
    * MetaData
    * @return String
    */
    protected String getStoreFileName(HttpServletRequest request,
    String fileName, MetaData parameters) {
    // 注意: 此处的代码仅用于演示上传文件的处理方式。
    // 以系统时间戳为文件命名并不能有效的避免文件重名!
    int pos = fileName.lastIndexOf(".");
    String extName;
    if (pos > 0) {
    extName = fileName.substring(pos);
    } else {
    extName = "";
    }
    String fullFileName = System.currentTimeMillis() + extName;
    return fullFileName;
    }

    /**
    * 存储已经上传的文件
    *
    * @param request
    * HttpServletRequest
    * @param fileItem
    * String
    * @param storeFile
    * String
    * @param parameters
    * MetaData
    * @throws Exception
    */
    @SuppressWarnings("unchecked")
    protected void storeUploadFile(HttpServletRequest request,
    FileItem fileItem, File storeFile, MetaData parameters)
    throws Exception {

    super.storeUploadFile(request, fileItem, storeFile, parameters);
    String filePath = UserConfig.getString("file_path")
    + storeFile.getName();

    String fileName = parameters.getString("fileName");

    if (fileName == null

    "".equals(fileName.trim())) {
    fileName = this.getFileName(fileItem.getName());
    } else {
    fileName = new String(fileName.getBytes("ISO8859-1"), "UTF-8");
    }
    String fileRemark = new String(parameters.getString("fileRemark")
    .getBytes("ISO8859-1"), "UTF-8");

    Map file=new HashMap();

    file.put("fileRemark", fileRemark);
    file.put("fileName", fileName);
    file.put("filePath", filePath);
    file.put("createDate", new Date());
    FileUploadViewModel.lstFiles.add(file);
    /**
    * 此处可进行文件信息持久化
    DBStatement dbst = new DBStatement();
    dbst.setSql(DBStatement.INSERT, "Gfile");
    dbst.parameters().setValue("fileRemark", fileRemark);
    dbst.parameters().setValue("fileName", fileName);
    dbst.parameters().setValue("filePath", filePath);
    dbst.parameters().setDate("createDate", new Date());
    dbst.execute();
    */
    }

    /**
    * 取得将要下载的文件的文件名
    *
    * @param request
    * HttpServletRequest
    * @return String
    */
    protected String getDownLoadFileName(HttpServletRequest request) {
    return "文件下载"
    + System.currentTimeMillis() + FOMART;
    }

    protected String getFileName(String fileName) throws Exception {
    fileName = fileName.substring(fileName.lastIndexOf("
    "
    ) + 1);
    fileName = fileName.substring(0, fileName.lastIndexOf("."));
    return fileName;
    }

    @Override
    protected InputStream getDownloadFileInputStream(HttpServletRequest request)
    throws Exception {
    this.FILEPATH=createFileZIP(request);
    return new FileInputStream(this.FILEPATH);
    }

    @Override
    protected void outputDownloadFile(HttpServletRequest arg0,
    HttpServletResponse arg1) throws IOException, Exception {
    super.outputDownloadFile(arg0, arg1);
    if(this.FILEPATH!=null&&UserConfig.getBoolean("file_delete")){
    File file=new File(this.FILEPATH);
    file.delete();
    }
    }

    /**
    * 生成文件压缩包,并返回压缩包地址
    * @param request
    * @param response
    * @return
    * @throws IOException
    */
    private String createFileZIP(HttpServletRequest request) throws IOException{
    List<File> lstFile = new ArrayList<File>();
    String filePaths = request.getParameter("fp");
    String fileNames = request.getParameter("fn");

    String[] strFileName = fileNames.split(",");
    String[] strFilePath = filePaths.split(",");
    int sign;

    File file = new File(UserConfig.getString("file_path"),this.getDownLoadFileName(request) );
    ZipOutputStream outputStream = new ZipOutputStream(
    new FileOutputStream(file));

    for (int i = 0; i < strFilePath.length; i++) {
    String filepath = strFilePath[i];
    String filename = strFileName[i] + filepath.substring(filepath.lastIndexOf("."));
    File tempFile=new File(filepath);
    ZipEntry entry = new ZipEntry(filename);
    outputStream.putNextEntry(entry);

    BufferedInputStream binputStream = new BufferedInputStream(
    new FileInputStream(tempFile));
    byte[] data = new byte[1024];
    sign = binputStream.read(data);
    while (sign != -1) {
    outputStream.write(data, 0, sign);
    sign = binputStream.read(data);
    }
    outputStream.closeEntry();
    binputStream.close();
    }
    outputStream.close();
    return file.getPath();
    }
    }

    此代码中包含存储上传文件方法storeUploadFile、下载文件方法outputDownloadFile、文件打包方法createFileZIP。
    如果上传成功将跳转到upload.jsp,代码如下:

    <%@ page contentType="text/html; charset=UTF-8" %>
    <html>
    <head>
    <title></title>
    <script language="JavaScript">
    /*var filePath="<%=request.getAttribute("filePath")%>";*/
    if(parent) parent.afterUpload();
    </script>
    </head>
    <body>
    </body>
    </html>

    调用file-upload.jsp中Function的afterUpload方法更新数据,代码如下:

    /**
    * 设置上传完成后更新dataset
    */
    function afterUpload(){
    dsFile.flushData();
    subwinAddFile.hide();
    }


  2. 在jsp中添加iframe如下:

    <iframe name="upload" style="display:none" ></iframe>

    将iframe隐藏,name与上面添加的form的target一致,uploadForm(form)的提交动作将在iframe中进行,这样上传文件时主页面不刷新功能基本实现。
  3. 建立菜单menuTop(menu)和menubarTop(menubar)。

代码如下:

<Control type="Menu" id="menuTop">
<MenuItem name="menuitemFileUpload" label="文件上传" path="javascript:dsFile.insertRecord();subwinAddFile.show(true,true);" />
<MenuItem name="menuitemFileDownload" label="文件下载" path="javascript:downloadFile(dsFile);" />
<MenuItem name="menuitemFileDelete" path="javascript:deleteFile(dsFile);" label="文件删除" />
</Control>

调用Function中方法:

/**
* 下载dataset中选中的记录
* @param dataset 记录集
*/
function downloadFile(dataset){
var filePath="";
var fileName="";
dataset.disableControls();
var current = dataset.getCurrent();
try {
dataset.moveFirst();
while (!dataset.isLast()) {
if(dataset.getValue("select")==true){
filePath+=dataset.getValue("filePath")+",";
fileName+=dataset.getValue("fileName")+",";
}
dataset.moveNext();
}
}
finally {
dataset.setCurrent(current);
dataset.enableControls();
}
if(filePath.length>0){
filePath=encodeURIComponent(filePath.substring(0,filePath.length-1));
fileName=encodeURIComponent(fileName.substring(0,fileName.length-1));
}else{
alert("请选择要下载文件!");
return;
}
filePath="uploadFile.download.d?fp="+filePath+"&fn="+fileName;
cmdFileDownload.setPath(filePath);
cmdFileDownload.execute();
}
/**
* 删除dataset中选中的记录
* @param dataset 记录集
*/
function deleteFile(dataset){
var selectedFile=false;
dataset.disableControls();
var current = dataset.getCurrent();
try {
dataset.moveFirst();
while (!dataset.isLast()) {
if(dataset.getValue("select")==true){
selectedFile=true;
}
dataset.moveNext();
}
}
finally {
dataset.setCurrent(current);
dataset.enableControls();
}
if(selectedFile){
cmdFileDelete.execute();
}else{
alert("请选择要删除的文件!");
}
}

  1. 建立cmdFileDownload(RequestCommand)和cmdFileDelete(UpdateCommand)。

cmdFileDownload代码如下:

<Control method="post" id="cmdFileDownload" type="RequestCommand">
<Frame />
<Parameters />
</Control>

cmdFileDelete代码如下:

<Control id="cmdFileDelete" type="UpdateCommand" method="deleteFile" async="true">
<DatasetInfos>
<DatasetInfo dataset="dsFile" submitScope="selected" flushDataOnSuccess="true" />
</DatasetInfos>
<Parameters />
</Control>

Viewmodel中的deleteFile方法代码如下:

public void deleteFile(ParameterSet parameters, ParameterSet outparameters)
throws Exception {
String filePath = "";
String message="文件删除成功!";
HttpDoradoContext context = (HttpDoradoContext) DoradoContext
.getContext();
HttpServletRequest request = context.getRequest();
String webappPath = request.getSession().getServletContext()
.getRealPath("/");
ViewDataset dataset = this.getDataset("dsFile");

dataset.moveFirst();
try {
while (!dataset.isLast()) {
filePath = dataset.getValue("filePath").toString();
System.out.println(filePath);
File file = new File(filePath);
if (file.exists()) {
for (int i = 0; i < this.lstFiles.size(); i++) {
Map mfile = (Map) this.lstFiles.get(info);
if (mfile.get("filePath").equals(filePath)) {
this.lstFiles.remove(info);
}
}
file.delete();
}
dataset.moveNext();
}
} catch (Exception e) {
message="文件删除发生异常!";
}

outparameters.setValue("$message", message);
}

*:如果输出参数key为$message,前台将以弹出框形式将value显示出来。

延伸思路:

正如上文所说,我们仍然可以将本例改造成多文件上传,每添加一个文件就动态生成fileEditor,后台代码也需要进行修改,如果你有兴趣可以尝试一下。