使用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>
要点说明:
- create标签的creator属性有多种属性值,比较常用的是new,还有spring【与Spring集成的时候就选择这个】。
- param标签常用name属性设置为class,value指定为要公布的完全限定类名。
- include标签指定该类中要公布的方法名称,exclude标签指定该类中不公布的方法名称。
- 当选择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>
问题说明:
文件下载的时候,如果使用外部下载器(诸如迅雷、旋风)则无法进行下载,提示任务出错。而使用浏览器内置下载器可以正常下载,目前原因不知,如果你知道原因,欢迎指出!
七、 功能测试
文件上传
文件下载
原创声明:
本文为个人原创,如有错误与不妥,欢迎提出!
另外,未经许可,谢绝转载。
- 使用DWR框架完成文件上传与下载
- SSH框架下使用Commons FileUpload控件完成多文件上传与下载
- DWR文件上传和下载
- 使用Struts2框架进行文件的上传与下载
- 网络:ASI 框架使用(上传与下载文件)
- Struts2框架11.文件上传与下载
- 使用FTP命令自动完成文件的上传和下载
- DWR框架搭建与使用
- DWR框架搭建与使用
- Android 使用AsyncHttpClient文件上传与下载
- iOS 之asi 框架 文件 的上传与下载
- 基于struts框架的文件上传与下载代码
- 框架(一)struts2——文件上传与下载
- java框架Struts学习--文件上传与下载
- 文件上传与下载----上传
- 文件上传与下载
- 文件上传与下载
- 上传与下载文件
- Hibernate ID 注解
- C++中的extern "C"声明简介
- 【JEECG技术博文】jeecg 定时任务配置用法
- C++模板
- spark配置优化
- 使用DWR框架完成文件上传与下载
- 微信接收消息与返回给微信的消息中的tousername、fromusername的值
- UIViewController的生命周期及iOS程序执行顺序
- 使用AsyncDisplayKit提升UICollectionView和UITableView的滚动性能
- 搭建项目
- 笔记
- shell 生成指定范围随机数与随机字符串
- 输入输出流getOutputStream() has already been called for this response问题的解决办法
- xcode7.2 真机调试注意点