使用DWR框架完成文件上传与下载

来源:互联网 发布:iphone装机必备软件 编辑:程序博客网 时间:2024/05/21 04:38

本文主要介绍使用ajax框架——DWR完成文件的上传与下载

一、  创建Maven模块

    这里不详述过程


二、  编辑pom.xml

    下面罗列我所需要用到的依赖

        <!-- 首先是Servlet-API的依赖 -->        <dependency>            <groupId>javax</groupId>            <artifactId>javaee-web-api</artifactId>            <version>7.0</version>            <scope>provided</scope>        </dependency>        <!-- DWR框架的依赖 -->        <dependency>            <groupId>org.directwebremoting</groupId>            <artifactId>dwr</artifactId>            <version>3.0.1-RELEASE</version>        </dependency>        <!-- DWR依赖于commons-logging,所以还必须有commons-logging这个包 -->        <dependency>            <groupId>commons-logging</groupId>            <artifactId>commons-logging</artifactId>            <version>1.2</version>        </dependency>        <!-- 文件上传依赖 -->        <dependency>            <groupId>commons-fileupload</groupId>            <artifactId>commons-fileupload</artifactId>            <version>1.3.1</version>        </dependency>        <!-- 文件MIME类型检测依赖 -->        <dependency>            <groupId>org.apache.tika</groupId>            <artifactId>tika-core</artifactId>            <version>1.12</version>        </dependency>        <!-- 常用工具包 -->        <dependency>            <groupId>commons-lang</groupId>            <artifactId>commons-lang</artifactId>            <version>2.6</version>        </dependency>

    另外我使用了jetty作为Web容器

  <plugin>      <groupId>org.eclipse.jetty</groupId>      <artifactId>jetty-maven-plugin</artifactId>      <version>9.2.10.v20150310</version>      <configuration>      <webAppConfig>          <contextPath>/dwr</contextPath>      </webAppConfig>      <httpConnector>          <port>8787</port>      </httpConnector>      <scanIntervalSeconds>10</scanIntervalSeconds>      <stopKey>terminate</stopKey>      <stopPort>7878</stopPort>      </configuration>  </plugin>

三、  编辑web.xml

    注册DWR的监听器【这里DWR的监听器并非必须】和Servlet。

    <!-- 注册DWR的监听器,注意不同版本的DWR监听器注册方式不同 -->    <listener>        <listener-class>org.directwebremoting.servlet.DwrListener</listener-class>    </listener>    <!-- 注册DWR的Servlet -->    <servlet>        <servlet-name>dwr-invoker</servlet-name>        <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>        <!-- 指定最大上传为10M -->         <init-param>            <param-name>fileUploadMaxBytes</param-name>            <param-value>104857600</param-value>        </init-param>        <!-- 开发环境中可以打开debug,生产环境中一般要关闭 -->         <init-param>            <param-name>debug</param-name>            <param-value>true</param-value>        </init-param>        <!-- 容器启动时就加载并初始化DWR的Servlet -->        <load-on-startup>1</load-on-startup>    </servlet>    <servlet-mapping>        <servlet-name>dwr-invoker</servlet-name>        <url-pattern>/dwr/*</url-pattern>    </servlet-mapping>

    顺带一提:我使用的DWR是3.0.1-REALEASE版本,另外用的比较多的还有3.0.M1里程碑版本。这两个版本对监听器的注册有所不同, 3.0.M1版本没有DwrListener这个类, 需要由另外两个监听器来实现,这里不展开,有需要的话可以Google、百度。【不知道是不是不同Maven镜像下载下来的依赖略有不同,因为我有朋友使用3.0.M1版本就有DwrListener这个类】


四、  编写文件上传与下载的服务类

    文件上传UploadService.java

/** * @Date : 2016-03-15 9:57 * @Author : junbin chung * @Email : seraphstorm@163.com * @Intro : 提供文件批量上传服务 */public class UploadService {    /**     * 功能:根据文件传输器批量上传文件到webapp/upload目录下     *     * @param fileTransfers 从页面传递过来的DWR的文件传输器数组     * @throws IOException     */    public void batchUpload(FileTransfer[] fileTransfers) throws IOException {        // 通过webContext可以获得Servlet API的大多数常用对象        WebContext webContext = WebContextFactory.get();        String realPath = webContext.getServletContext().getRealPath("/upload");        for (FileTransfer fileTransfer : fileTransfers) {            String name = FilenameUtils.getName(fileTransfer.getFilename());            // 如果没有选择文件,则文件名为空,故不应该为它作上传处理            if (StringUtils.isEmpty(name)) {                continue;            }            InputStream inputStream = fileTransfer.getInputStream();            FileUtils.copyInputStreamToFile(inputStream, new File(realPath, name));        }    }

    这里说明一下,文件上传接收的参数除了FileTransfer类型之外,还有一个比较常用的类型是InputStream。但是由于FileTransfer可以获得更多的信息,所以一般采用FileTransfer类型。


    文件下载Download.java

/** * @Date : 2016-03-15 9:59 * @Author : junbin chung * @Email : seraphstorm@163.com * @Intro : 提供文件下载服务 */public class DownloadService {    /**     * 功能:获取webapp/upload目录下的文件名称列表     *     * @return 文件名称列表     */    public String[] listFiles() {        WebContext webContext = WebContextFactory.get();        String realPath = webContext.getServletContext().getRealPath("/upload");        File dir = new File(realPath);        return dir.list();    }    /**     * 功能:根据指定名称获取文件并提供下载     *     * @param filename 文件名称     * @return DWR文件传输器     * @throws IOException     */    public FileTransfer downloadFile(String filename) throws IOException {        WebContext webContext = WebContextFactory.get();        String realPath = webContext.getServletContext().getRealPath("/upload");        File file = new File(realPath, filename);        if (file.exists() && file.isFile()) {            // 使用Tika检测文件的MIME            Tika tika = new Tika(TikaConfig.getDefaultConfig());            return new FileTransfer(new String(filename.getBytes("UTF-8"), "ISO-8859-1"), // 转化字符编码,避免中文乱码                    tika.detect(file), file.length(), new FileInputStream(file));        }        throw new FileNotFoundException("文件名称:" + filename                + "\n对不起,资源已被删除或者不再提供该资源的下载服务!");    }}

五、  在dwr.xml中公布Service类

    其一、我们需要在webapp/WEB-INF/目录下创建一个dwr.xml文件并引入DWR的dtd
    其二、公布UploadService和DownloadService。

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN"        "http://getahead.org/dwr/dwr30.dtd"><dwr>    <allow>        <!-- 暴露UploadService和DownloadService为外部可安全引用的 -->        <create creator="new">            <param name="class" value="org.junbin.dwr_in_action.service.UploadService"/>            <include method="batchUpload"/>        </create>        <create creator="new">            <param name="class" value="org.junbin.dwr_in_action.service.DownloadService"/>            <include method="listFiles"/>            <include method="downloadFile"/>        </create>    </allow></dwr>

    要点说明:

  1. create标签的creator属性有多种属性值,比较常用的是new,还有spring【与Spring集成的时候就选择这个】。
  2. param标签常用name属性设置为class,value指定为要公布的完全限定类名。
  3. include标签指定该类中要公布的方法名称,exclude标签指定该类中不公布的方法名称。
  4. 当选择new的时候,需要确保该类有一个无参构造方法【隐式或者显式】;通常建议使用include标签。

六、  编辑文件上传下载的jsp文件

    6.1、文件上传upload.jsp
        6.1.1、引入js文件

<head>    <title>文件上传</title>    <script type="text/javascript" src="${pageContext.request.contextPath}/static/js/jquery-1.8.3.js"></script>    <!-- 必须引入DWR的engine.js -->    <script type="text/javascript" src="${pageContext.request.contextPath}/dwr/engine.js"></script>    <!-- 引入之前在dwr.xml中公布的Service,名称为:interface/ClassName.js -->    <script type="text/javascript" src="<%=request.getContextPath()%>/dwr/interface/UploadService.js"></script></head>

        6.1.2、文件上传div

<div id="batch">    <label>请选择文件:<input type="file" name="batch"/></label><br/>    <button id="append" type="button">继续添加</button>    <button id="upload" type="button">上传</button></div>

        6.1.3、DWR处理批量上传

<script type="text/javascript">    $(function () {        var batch = $("#batch");        batch.on("click", "#append", function (event) {            event.stopPropagation();            batch.find("#append").before("<label>请选择文件:<input type=\"file\" name=\"batch\"/></label><br/>");        });        batch.on("click", "#upload", function (event) {            event.stopPropagation();            // 第一步:获取上传文件的jQuery包装集            var jQueryBatchFile = $("input[type='file'][name='batch']");            // 第二步:将jQuery包装集转换成DOM对象            var batchFile = [];            for (var i = 0; i < jQueryBatchFile.length; i++) {                batchFile[i] = jQueryBatchFile[i];            }            // 第三步:使用DWR完成文件异步上传            UploadService.batchUpload(batchFile, function () {                // 第四步:清空并保留一项文件上传项                batch.find("label:gt(0)").remove();                batch.find("input[type='file']:gt(0)").remove();                batch.find("br:gt(0)").remove();                batch.find("input[type='file']:eq(0)").val("");            });        });    });</script>

    要点说明:
        传递到服务器端的文件对象是DOM对象而不是jQuery包装集,所以如果不将jQuery包装集转成DOM对象是无法完成上传操作的。
        浏览器支持问题,在webkit内核的浏览器(诸如chrome、360)中无法完成上传。在经过搜索之后发现,需要在js代码中添加一个函数:

dwr.engine.transport.iframe.loadingComplete = function (batchId) {    var isChrome = (/\bchrome\b/).test(navigator.userAgent.toLowerCase());    var batch = dwr.engine._batches[batchId];    if (!isChrome)        if (batch) dwr.engine.batch.validate(batch);};

        这样就可以在chrome和360中正常完成上传功能了,参考来源:http://pengjj2.iteye.com/blog/1275201
        另外这个问题还有部分人提出更新DWR至最新版本就可以了。但是,我从原来的3.0.M1更新了最新版的3.0.1-RELEASE版本之后依然不行。至于在上面的upload.jsp中没有追加该方法,是因为我直接在DWR的engine.js源码上面做了修改。


    6.2、文件下载download.jsp
        6.2.1、引入js文件

<head>    <title>文件下载</title>    <script type="text/javascript" src="${pageContext.request.contextPath}/static/js/jquery-1.8.3.js"></script>    <script type="text/javascript" src="${pageContext.request.contextPath}/dwr/engine.js"></script>    <script type="text/javascript" src="${pageContext.request.contextPath}/dwr/interface/DownloadService.js"></script>    <!-- 导入外部样式表 -->    <link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/static/css/download.css"/></head>

        6.2.2、文件下载div

<div>    <button id="list" type="button">罗列可下载文件</button>    <br/>    <hr/>    <table id="files">        <thead>        <tr>            <th>文件名</th>            <th>操作</th>        </tr>        </thead>        <tbody>        </tbody>    </table></div>

        6.2.3、DWR处理文件下载

<script type="text/javascript">    $(function () {        $("body > div").on("click", "#list", function (event) {            event.stopPropagation();            DownloadService.listFiles(function (responseTxt) {                var filenameArr = responseTxt;                // 第一步:罗列DWR传递过来的文件名称到tbody的第一列中                var tbodyContent = "";                for (var i = 0; i < filenameArr.length; i++) {                    tbodyContent += "<tr><td>";                    tbodyContent += filenameArr[i];                    tbodyContent += "</td><td></td></tr>";                }                $("tbody").html(tbodyContent);                // 第二步:为tbody每一行的第二列追加一个下载按钮                var btn = $("<button type='button'>下载</button>");                var rows = $("tbody tr");                for (i = 0; i < rows.length; i++) {                    $(rows[i]).find("td:nth-child(2)").append(btn.clone());                }            });        });        $("tbody").on("click", "button", function (event) {            event.stopPropagation();            // 第一步:获取要下载的文件名称            var filename = $(this).parent().prev("td").html();            // 第二步:使用DWR完成文件下载            DownloadService.downloadFile(filename, {                // 使用DWR创建iframe下载文件                callback: function (responseFile) {                    dwr.engine.openInDownload(responseFile);                },                // 异常处理                errorHandler: function (msg, e) {                    // 弹出警告框显示错误信息                    alert(msg);                    // 控制台打印错误发生位置                    console.log(e.stackTrace[0]);                },                // 不使用异步请求                async: false            });        })    });</script>

    问题说明:
        文件下载的时候,如果使用外部下载器(诸如迅雷、旋风)则无法进行下载,提示任务出错。而使用浏览器内置下载器可以正常下载,目前原因不知,如果你知道原因,欢迎指出!


七、  功能测试

    文件上传

文件上传


    文件下载

文件下载


原创声明:

    本文为个人原创,如有错误与不妥,欢迎提出!
    另外,未经许可,谢绝转载。

发布日期:2016年3月17日
0 0
原创粉丝点击