项目需求里面要求实现一个类似于excel里透视表的功能,大致意思就是选择对应的数据库之后,行标签和列标签都是可选的,然后在页面上就生成对应的相关记录。
例如,我选择“财务信息”数据库,列标签选择“部门”,行标签选择“科目”,页面上就显示每个部门在每项科目上的财务信息(这里就简单化为支出)。

因为我前台选择的是easyui框架,一般用于显示表格都是在datagrid的columns定义filed和title,但是这个需求就无法事先定义好这些属性,只有在运行时才能装载这些组件,怎么办呢?看了很多网上的信息,发现讲的都很模糊,要不就是简单问题复杂化,要不就是一言带过,于是就决定自己弄,毕竟看别人的东西只是个启发。废话不多说,开始。

难点:

1.前台js动态生成datagrid配置
2.后台json动态装配

解决办法:

对于第一个难点,
弄懂核心原理是最重要的,核心就是 重新生成column字符串。意思就是说,原先是前台js事先写死,但是现在传一个值过去,格式和原先保持一致就可以了。
既然知道这个原理了,那问题就迎刃而解了,我先调用后台处理方法,再返回对应格式的字符串给前台就行了。即保证前台获取的json格式如下:

[html]   

  1. {"total":23,  

  2. "rows":[  

  3. {"3":0,"2":91940.0,"1":0,"4":50000.0,"detailSubject":"01.1 购置设备费"},  

  4. {"3":36000.0,"2":0,"1":80000.0,"4":0,"detailSubject":"01.2 研制设备费"}],  

  5. "columns":[[{"field":"detailSubject","width":100,"title":"明细科目"},  

  6. {"field":"1","width":100,"title":"D0 材料部"},  

  7. {"field":"2","width":100,"title":"D1 工程部"},  

  8. {"field":"3","width":100,"title":"D2 软件部"},  

  9. {"field":"4","width":100,"title":"D3 物理部"}]]  

  10. }  


下面是实现的两种前台的写法:
第一种前台写法:

[javascript]   

  1. $(function(){  

  2.         //初始化  

  3.         $("#pivotTable_datagrid").datagrid({  

  4.             type: 'POST',  

  5.             pagination:true,  

  6.             rownumbers:true,  

  7.             fit:true,  

  8.             width:1024,    

  9.             height:500,    

  10.             nowrap: false,  

  11.             border: false,  

  12.             pageSize:10,  

  13.             singleSelect:true  

  14.         });      

  15.         loadDatagrid();  

  16.     });  

  17.   

  18.     function loadDatagrid() {  

  19.         $.ajax({  

  20.              url: path+'/pivotTable/datagrid',  

  21.              type:"POST",    

  22.              success: function(data){  

  23.                 var options = $("#pivotTable_datagrid").datagrid("options"); //取出当前datagrid的配置       

  24.                 var json = decodeURIComponent(data.columns);//解码  

  25.                 console.info(json);  

  26.                 options.columns = eval(json);  

  27.                  $('#pivotTable_datagrid').datagrid(options);  

  28.                 $('#pivotTable_datagrid').datagrid("loadData", data.rows);//实例化之后立刻载入数据源,加载本地数据,旧的行会被移除。  

  29.              }  

  30.         });  

  31.     }  


这一种方法主要是把后台传过来的column对应的json数组通过options赋给datagrid的column属性,然后再重新.datagrid(),这个方法有个缺陷,就是没法实现刷新
因为项目工期比较紧,我就没有仔细研究为什么会这样。下面介绍下另一种写法,其实原理还是一样的,从后台获取column的json配置:
  

  1. /** 

  2.     * 生成透视表, 

  3.     */  

  4.    function create() {  

  5.        var database = $('#pivotTable_searchForm input[name=database]').val();  

  6.        var colTag = $('#pivotTable_searchForm input[name=colTag]').val();  

  7.        var rowTag = $('#pivotTable_searchForm input[name=rowTag]').val();  

  8.        console.info(database);  

  9.        if (database.trim() == "") {  

  10.            $.messager.alert('提示''请先选择数据源!''info');  

  11.        }else if(colTag.trim() == "" && rowTag.trim() == ""){  

  12.            $.messager.alert('提示''请至少选择一个行标签或者列标签!''info');  

  13.        }else if(colTag.trim() == rowTag.trim()){  

  14.            $.messager.alert('提示''亲,行标签和列标签不能一样哦!''info');  

  15.        }else{  

  16.            console.info(database);  

  17.            console.info(colTag);  

  18.            console.info(rowTag);  

  19.            var url = path+'/pivotTable/datagrid?database='+database  

  20.                +'&colTag='+colTag+'&rowTag='+rowTag;  

  21.            $.ajax({  

  22.                url : url,  

  23.                dateType : 'json',  

  24.                type : 'post',  

  25.                success : function(r) {  

  26.                    console.info(r.columns);  

  27.                    $('#pivotTable_datagrid').datagrid({  

  28.                        url : url,  

  29.                        fit : true,  

  30.                        border : false,  

  31.                        pagination : true,  

  32.                        rownumbers : true,  

  33.                        fitColumns : true,  

  34.                        columns : r.columns   //这里提取后台传过来的json数组里的columns数据,  

  35.                    });  

  36.                }  

  37.            });  

  38.        }  

  39.    }  

这样第一个难点就解决了,只要后台传过来的json格式正确,前台就能显示对应的界面。那么问题来了,学挖掘机技术哪家强?好吧,开个玩笑^_^

        第二个难点,我怎么在后台生成动态的column的json?(因为笔者是用java的springmvc写的,所以可能下面方法只适合javaer)

很简单,如果实体类的属性知道,就一个通过java反射获取,填充到column的field的属性里。先看代码:    
后台:
       

  1.     /** 

  2.      * 生成透视表 

  3.      * @return 

  4.      */  

  5.     @ResponseBody  

  6.     @RequestMapping("/pivotTable/datagrid")  

  7.     public DataGrid testPage(PageHelper page,HttpServletRequest request){  

  8.         DataGrid dg = new DataGrid();            //这个是用于向前台传送整个json数据的实体bean  

  9.         PageHelper page = new PageHelper();        //用于后台分页的  

  10.           

  11.         List<DatagridColumn> columnList = new ArrayList<DatagridColumn>();  

  12.         Map<String,String> column = new HashMap<String,String>();  

  13.         column.put("applyDate""日期");  

  14.         column.put("proBriefName""项目简称");  

  15.         column.put("activityCode""财务计划编号");  

  16.         column.put("applicant""申请人");  

  17.         column.put("amount""金额");  

  18.         column.put("fundPurpose""经费用途");  

  19.         column.put("loanNo""借款单号");  

  20.         // 获取实体类的所有属性,返回Field数组    

  21.         LoanBean t = new LoanBean();  

  22.         Field[] field = t.getClass().getDeclaredFields();    

  23.         // 遍历所有属性    

  24.         for (int j = 0; j < field.length; j++) {  

  25.             DatagridColumn dc = new DatagridColumn();  

  26.             // 获取属性的名字  

  27.             String name = field[j].getName();    

  28.             dc.setField(name);  

  29.             dc.setTitle(column.get(name));  

  30.             dc.setWidth(80);  

  31.             columnList.add(dc);  

  32.         }  

  33.         String columnJson = JSON.toJSONString(columnList, SerializerFeature.UseSingleQuotes);  

  34.         System.out.println("json格式的column为:"+columnJson);  

  35.         columnJson = "["+columnJson+"]";  

  36.         /* 

  37.         //columns需要后台生成 

  38.         String columns = "[["; 

  39.         columns = columns + "{field:'applyDate',title:'日期',width:80},"; 

  40.         columns = columns + "{field:'proBriefName',title:'项目简称',width:80},"; 

  41.         columns = columns + "{field:'activityCode',title:'财务计划编号',width:80},"; 

  42.         columns = columns + "{field:'applicant',title:'申请人',width:80},"; 

  43.         columns = columns + "{field:'amount',title:'金额',width:80},"; 

  44.         columns = columns + "{field:'fundPurpose',title:'经费用途',width:80},"; 

  45.         columns = columns + "{field:'loanNo',title:'借款单号',width:80}"; 

  46.         columns = columns + "]]"; 

  47.         */  

  48.         try {  

  49.             columnJson = URLEncoder.encode(columnJson,"UTF-8");  

  50.         } catch (UnsupportedEncodingException e) {  

  51.             e.printStackTrace();  

  52.         }  

  53.         System.out.println(columnJson);  

  54.         //根据条件查询总数  

  55.         Long total = financeService.loanCount(page);  

  56.         dg.setTotal(total);  

  57.         //根据条件查询List  

  58.         List<LoanBean> loanList = financeService.loanList(page);//这里是重点  

  59.         dg.setRows(loanList);  

  60.         dg.setColumns(columnJson);  

  61.         return dg;  

之前都是用实体bean加载记录数据,再放到datagrid的rows里面,然后springmvc的jackson自动将其序列化为json数组传到前台,
但是现在如果实体类的属性不固定(大多数情况下都是这个),该怎么办?我这里给个思路:
我用了一个ResultBean来加载返回的结果记录集,这个ResultBean里有两个属性,第一个是记录的第一列的标题rowTag,第二个属性就是自第二列之后每一列下的值,因为列数不固定,所以就用了Map<String,Object> data来获取,后台查出几个记录,就put对应的kew,value进去,最后再写个方法,根据结果集、表头Title和Field映射Map、行标签,生成Map类型的rows,这个转换方法核心就是遍历map再加载,如下:
  

  1. /** 

  2.   * 根据结果集、表头Title和Field映射Map、行标签,生成Map类型的rows 

  3.   * @param rlist 

  4.   * @param colMap 

  5.   * @param rowTag 

  6.   * @return 

  7.   */  

  8.  public List<Map<String, Object>> getDatagridMap(List<ResultBean> rlist,  

  9.          Map<String, String> colMap, String rowTag) {  

  10.      List<Map<String,Object>> datagridMap = new ArrayList<Map<String,Object>>();  

  11.      for(int i=0;i<rlist.size();i++){  

  12.          Map<String,Object> rMap= new HashMap<String, Object>();  

  13.          ResultBean rb = rlist.get(i);  

  14.          rMap.put(rowTag, rb.getRowTag());  

  15.          //遍历Map  

  16.          Set<String> set1 = rb.getData().keySet();  

  17.          Iterator<String> it = set1.iterator();  

  18.          while(it.hasNext()){  

  19.              String colTitle = it.next();  

  20.              if(colMap.containsKey(colTitle)){  

  21.                  rMap.put(colMap.get(colTitle), rb.getData().get(colTitle));  

  22.              }  

  23.          }  

  24.          datagridMap.add(rMap);  

  25.      }  

  26.      return datagridMap;  

  27.  }  

    总之,一句话,原理最重要,后台返回对应的json格式(注意,json格式是最核心的),前台就能生成相应的界面。至于json数据怎么生成,不同的人有不同的实现方式。哦了!