DataTables+Struts+Ajax技术的文件下载实现

1.问题分析:

通过Datatables控件所展示的数据,如果在defaultContent一列中打算通过ajax请求完成基于Strut的文件下载,则由于Strut框架特性,常常出现文件被浏览器直接打开的问题。(即使在对应的Action进行了attachment配置也不可行)


2.问题解决原理:
Datatables的ajax请求仅用于发送到查找文件的Action(Ac1),并通过Ac1返回一个真正可以下载文件url,在success回调中调用windows.open方式打开,从而将异步请求改为了同步请求。其实现原理图如下所示:

3.代码说明
1.包含DataTable的Ajax请求Jsp页面
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>检定标准管理界面</title>
<link rel="stylesheet" type="text/css" href="css/jquery.dataTables.css">
<script type="text/javascript" charset="utf8"src="js/LibJS/jquery.min.js"></script>
<script type="text/javascript" charset="utf8"src="js/LibJS/jquery.dataTables.js"></script>
</head>
<body>
    <!-- Html 标签用于静态创建table 元素  id为用于Js的初始化 -->
    <table id="example" class="display" cellspacing="0" width="100%">
        <thead>
            <tr>
                <th>标准设备类型</th>
                <th>标准名称</th>
                <th>标准适用设备</th>
                <th>标准文件名</th>
                <th>其他操作</th>
            </tr>
        </thead>
        <tbody></tbody>
        <!-- 必须包含 tbody节点-->
    </table>
    <!-- 利用Jquery 完成Datatable控件初始化与异步数据请求 -->
    <script type="text/javascript">
    $(document).ready(
            function() 
            {
                //表格初始化方法
                var table=$("#example").DataTable(
                {
                //指定ajax相关参数,url即相应的action dataSrc为Json结果的keyname值
                "ajax" : {
                        "url" : "StandardScan.action",//用于获取数据Action,
                        "dataSrc" : "ResultJson"
                          },
                    //将Json结果数据集的key绑定到对应列中,注意大小写对应 
                    "columns" : [
                    {"data" : "devicetype"},
                    {"data" : "chineseName"},
                    {"data" : "applyDevice"},
                    {"data" : "fileName"},
                    //对于非数据的元素,可以通过指定html标签的形式完成
                    {"defaultContent" : "<a href=\"#\" id='export'>导出</a>"}]
                });
                //导出按钮事件监听
                $("#example tbody").on( "click", "#export", 
                function () 
                {  
                     var data=table.row($(this).parents('tr')).data()//获取单击行的数据
                     var devicetype=data.devicetype;//获取关键值
                     var fileName=data.fileName;
                     //执行异步删除请求
                     $.ajax({  
                         url:"StandardExport", //完成待下载文件查找的Action1 
                         type: "post",
                         dataType : "text", //注意这里返回的text记录,即真正用于完成文件下载的url请求
                         data:
                         {
                              //传递文件查找关键字
                             "devicetype":devicetype,
                             "filename":fileName
                         },
                         success: function(result)
                         {   
                             //通过返回的用url再次向服务器发送文件下载请求(确保该url,由http://开头,否则浏览器不能解析)
                             window.open(result.toString())
                         },
                         error: function(result)
                         {
                             alert("服务器异常,请检查服务器状态");
                         } 
                         });  
                 });
            });
    </script>
</body>
</html>
2.用于查找待下载文件并返回下载url的Ac_StandardExport 
/**
 * 用于标准文件导出的Action,实际此Action只用于合成文件下载的url,具体下载执行操作由Ac_Download执行
 * @author cyoubo
 *
 */
public class Ac_StandardExport extends ActionSupport implements Preparable
{
    private static final long serialVersionUID = 107971309744984424L;
    //查询服务
    private IStandardQuery Query;
    //文件关键字
    private String devicetype;
    private String fileName;
    @Override
    public void prepare() throws Exception
    {
        //获取项目Standard主文件夹
        String standardfold=ServletActionContext.getServletContext().getRealPath("/")+"Standard/";
        //构建查询服务
        Query=new StandardQuery(standardfold);    
    }
    @Override
    public String execute() throws Exception
    {
        //准备返回文件下载的url字符串的输出流
        HttpServletResponse response = ServletActionContext.getResponse();  
        response.setContentType("text/html;charset=UTF-8");  
        PrintWriter out = response.getWriter();  
        //判断当前标准文件是否存在
        if(Query.findStandFile(DeviceType.createFromChinese(devicetype), fileName)!=null)
            //生成下载用Url(combineStandardFullPath方法在本例中用于合成待下载文件在服务器中的路径)
            out.print(Ac_Download.getActionUrl(combineStandardFullPath()));
        else 
            out.print("Error");
        return null;//由于返回的字符串,此处必须返回null以表示没有待跳转页面
    }
    /**
     * @return 合成标准文件文件的完整路径
     */
    private String combineStandardFullPath()
    {
        return "Standard/"+DeviceType.createFromChinese(devicetype).name().toUpperCase()+"/"+fileName+".xml";
    }
    //getter与setter 方法省略
}
3.用于基于Strut框架实现文件下载的Action_Dowload
/**
 * 用于实现文件的专用Action,一般由getActionUrl(String fullPath)调用文件下载操作
 * @author cyoubo
 */
public class Ac_Download extends ActionSupport
{
    private static final long serialVersionUID = 3970709669947735057L;
    /**
     * 下载文件的文件名,建议Strut.xml的action配置文件中指定fileName=${fileName},以指定下载对话框的文件名
     */
    private String fileName;
    /**
     * 现在文件在服务器中的全路径,
     */
    private String fullPath;
    /**
     * @return 获取下载文件流对象
     * @throws UnsupportedEncodingException
     */
    public InputStream getDownloadFile() throws UnsupportedEncodingException
    {
        //从传递的文件全路径中获取文件名,用于在下载对话框中展示
        String[] item=FileUtils.splitFullPath2(fullPath);
        this.fileName=item[1]+"."+item[2];
        //防止中文文件名为乱码的问题
        this.fileName = new String(this.fileName.getBytes("GBK"),"ISO-8859-1");  
        return ServletActionContext.getServletContext().getResourceAsStream(fullPath) ;  
    }
     //getter与setter 方法省略
    /**
     * 获取文件下载请求的url
     * @param fullPath 从RootWeb目录开始(不包含RootWeb)的待下载文件全路径
     * @return 可以开启文件下载Ac_Download action的url
     */
    public static String getActionUrl(String fullPath)
    {
        return "http://localhost:8081/ExDevice2/FileDownloadAction.action?fullPath="+fullPath;
    }
}
4.Strut.xml配置文件
<package name="StandardPackage" extends="struts-default">
        <action name="StandardExport" class="com.dr.standard.action.Ac_StandardExport"></action>
<span style="white-space:pre">	</span><!-- 注意该Action没有结果JSP-->
    </package>
  
    <package name="OtherFunction" extends="struts-default">
         <!-- 标准文件下载Action的配置-->
        <action name="FileDownloadAction" class="com.dr.other.action.Ac_Download">
            <result name="success" type="stream">
                <param name="contentType">text/plain</param>
                <param name="contentDisposition">attachment;fileName="${fileName}"</param>
                <param name="inputName">downloadFile</param>
                <param name="bufferSize">1024</param>
            </result>
        </action>
    </package>





猜你喜欢

转载自blog.csdn.net/cyoubo/article/details/51791044