JQuery DataTable 結合SpringMVC+Spring Data JPA應用(二)

在上一節中配置好了DataTable的配置,接下來介紹關於後臺實現分頁、條件查詢、排序的方法。

DataTable後臺分頁、條件查詢、排序

1.DataTable參數的接收

後臺代碼需要接收的參數有:

  • 當前記錄數
  • 每頁顯示記錄
  • 排序的列(可能有多個)
  • 排序列的方向 ASC/DESC(可能有多個)
  • 當前請求次數
  • 排序列的數量
  • 自定義查詢的參數

然後再來看上一節中DataTable的基礎配置中,有以下代碼:

function retrieveData( sSource, aoData, fnCallback ) {     
        //查詢條件稱加入參數數組     
        var rentRuleId =document.getElementById('rentRuleId').value;  
        //alert(rentRuleId);
        $.ajax( {     
            type: "POST",
            url: sSource,   
            dataType:"json",  
            data: "jsonParam="+JSON.stringify(aoData)+"&isHistory=0&rentRuleId="+rentRuleId,  
            success: function(data) {   
               //$("#url_sortdata").val(data.aaData);  
                fnCallback(data); //服務器端返回的對象的returnObject部分是要求的格式     
            }     
        });    
    } 

這段代碼是是關鍵,它定義了關於DataTable的自己的參數適用jsonParam來接收,而關於自定義的查詢參數如isHistory、rentRuleId都適用相應的屬性來接收。但是也有一些方法是將這些參數放在aoData裏面,然後用同一個對象接收所有的數據。這裏先不考慮。
這時,相應的Controller就應該寫成這樣:
dataTableTestController.java

@RequestMapping(value = "/list", method = {RequestMethod.POST })
    protected void list(String jsonParam,ChargeRuleModel model,HttpServletResponse response){
        xxxx;//這裏避免干擾先不寫
    }

第一,通過ChargeRuleModel來接收自定義查詢的參數。
第二,用jsonParam來接受相應的jsonString。jsonParam的格式如下:

[{"name":"sEcho","value":1},            //請求次數
{"name":"iColumns","value":5},          //列數 
{"name":"sColumns","value":",,,,"},     //這個沒查到
{"name":"iDisplayStart","value":0},     //記錄起始,0表示第一條
{"name":"iDisplayLength","value":10},   //每頁顯示的記錄數
{"name":"mDataProp_0","value":"key"},   //第一列名稱 
{"name":"bSortable_0","value":false},   //第一列是否可以排序
{"name":"mDataProp_1","value":"rentRuleId"},//第二列名稱
{"name":"bSortable_1","value":true},    //第二列是否可以排序  
{"name":"mDataProp_2","value":"ruleName"},
{"name":"bSortable_2","value":true},
{"name":"mDataProp_3","value":"isEnable"},
{"name":"bSortable_3","value":true},
{"name":"mDataProp_4","value":"id"},
{"name":"bSortable_4","value":true},
{"name":"iSortCol_0","value":1},//第一個排序,value值得是第幾列 
{"name":"sSortDir_0","value":"asc"},//排序是正序還是倒敘
{"name":"iSortingCols","value":1}]  //一共有幾列排序

看出來了麼,其實是個JsonArray,所以常見的方法是這樣:

JSONArray ja = (JSONArray) JSONArray.parse(aoData);
        //分別爲關鍵的參數賦值
        for (int i = 0; i < ja.size(); i++) {
            JSONObject obj = (JSONObject) ja.get(i);
            if (obj.get("name").equals("sEcho"))
                sEcho = obj.get("value").toString();
            if (obj.get("name").equals("iDisplayStart"))
                iDisplayStart = obj.get("value").toString();
            if (obj.get("name").equals("iDisplayLength"))
                iDisplayLength = obj.get("value").toString();
            if (obj.get("name").equals("sSearch"))
                sSearch = obj.get("value").toString();
        }

對於一個JsonArray操作多麻煩,而且格式那麼統一,“name”、“value”讓人想起什麼?

protected Map<String,Object> covertJsonStringToHashMap(String jsonParam){
        JSONArray jsonArray = JSONArray.parseArray(jsonParam);
        Map<String,Object> map = Maps.newHashMap();
        for(int i=0;i<jsonArray.size();i++){
            JSONObject jsonObj = jsonArray.getJSONObject(i);
            map.put(jsonObj.getString("name"), jsonObj.get("value"));
        }
        return map;
    }

這時候考慮到可能有實現多個列的排序,另外不要再service再去判斷參數中第一列到底對應的是數據庫那個字段,所以就需要對於Map再進一步操作。這時引入一個對象 DataTableParameter。

public class DataTableParameter {
    private int sEcho; //請求服務器端次數
    private int iDisplayStart;//其實記錄,第一條爲0
    private int iDisplayLength;
    private int iColumns;
    private List<String> mDataProps; //列的Name列表
    private List<Boolean> bSortables;//列對應是否能排序
    private int iSortingCols;
    private List<Integer> iSortCols;    //排序列的編號
    private List<String> iSortColsName; //排序列的名稱
    private List<String> sSortDirs;     //排佈列排序形式 Asc/Desc
    ......
    //seter and getter
}

然後引入一個方法

protected DataTableParameter getDataTableParameterByJsonParam(String jsonParam){
        Map<String,Object> map = covertJsonStringToHashMap(jsonParam);
        int sEcho = (int) map.get("sEcho"); 
        int iDisplayStart = (int) map.get("iDisplayStart");
        int iDisplayLength = (int) map.get("iDisplayLength");
        int iColumns = (int)map.get("iColumns");
        int iSortingCols = (int)map.get("iSortingCols");

        List<String> mDataProps = Lists.newArrayList();
        List<Boolean> bSortables = Lists.newArrayList();
        for(int i=0;i<iColumns;i++){
            String dataProp = (String) map.get("mDataProp_"+i);
            Boolean sortable = (Boolean) map.get("bSortable_"+i);
            mDataProps.add(dataProp);
            bSortables.add(sortable);
        }

        List<Integer> iSortCols = Lists.newArrayList();
        List<String> sSortDirs = Lists.newArrayList();
        List<String> iSortColsName = Lists.newArrayList();
        for(int i=0;i<iSortingCols;i++){
            Integer sortCol = (Integer) map.get("iSortCol_"+i);
            String sortColName = mDataProps.get(sortCol);
            String sortDir = (String) map.get("sSortDir_"+i);
            iSortCols.add(sortCol);
            sSortDirs.add(sortDir);
            iSortColsName.add(sortColName);
        }

        return new DataTableParameter(sEcho, iDisplayStart, iDisplayLength, iColumns, mDataProps, bSortables, iSortingCols, iSortCols, sSortDirs,iSortColsName);
    }

這時Controller就變成這樣了:

@RequestMapping(value = "/list", method = {RequestMethod.POST })
    protected void list(String jsonParam,ChargeRuleModel model,HttpServletResponse response) {
        DataTableParameter dataTableParam = getDataTableParameterByJsonParam(jsonParam);
        //......
    }

參數接收處理完畢。

2.DataTable返回頁面參數

DataTable.java

public class DataTable<T>{

    private List<T> aaData;//數據
    private int iTotalDisplayRecords;//得到的記錄數
    private int iTotalRecords;//數據庫中記錄數
    private int sEcho; //請求服務器端次數
    //getter and setter
}

aaData接收相應的查詢返回結果,sEcho在請求一次後就加1.

完整的Controller方法如下:

@RequestMapping(value = "/list", method = {RequestMethod.POST })
    protected void list(String jsonParam,ChargeRuleModel model,HttpServletResponse response) {
        DataTableParameter dataTableParam = getDataTableParameterByJsonParam(jsonParam);
        List<ChargeRuleModel> aaData = chargeRuleService.list(model, dataTableParam);
        DataTable<ChargeRuleModel> dt = new DataTable<ChargeRuleModel>();
        int sEcho = dataTableParam.getsEcho()+1;
        dt.setAaData(aaData);
        dt.setsEcho(sEcho);
        dt.setiTotalDisplayRecords(aaData.size());
        dt.setiTotalRecords(aaData.size());
        response.setCharacterEncoding("utf-8");
response.getWriter().write(JSONObject.toJSONString(dt));
    }

3.動態查詢與分頁

Service方法如下:

public List<ChargeRuleModel> list(ChargeRuleModel model, DataTableParameter dataTableParam) {
        Pageable pageRequest = buildPageRequest(dataTableParam,ChargeRule.class);
        Specification<ChargeRule> spec = buildSpecification(model);
        List<ChargeRule> chargeRules = chargeRuleDao.findAll(spec, pageRequest).getContent();
        List<ChargeRuleModel> chargeRuleModels = null;
        // PO到VO的轉化
        Map<String, String> map = Maps.newHashMap();
        map.put("sourcePro1", "ruleAppliType.id");
        map.put("targetPro1", "ruleAppliTypePK");
        map.put("sourcePro2", "ruleAppliType.name");
        map.put("targetPro2", "ruleAppliTypeName");

        chargeRuleModels = BeanUtils.copyPropertiesBylist(chargeRules, ChargeRuleModel.class, map);
        return chargeRuleModels;
    }

    private Specification<ChargeRule> buildSpecification(ChargeRuleModel model) {
        String rentRuleId = model.getRentRuleId();
        boolean isHistory = model.getIsHistory();
        String historyRentRuleId = model.getHistoryRentRuleId();

        return new Specification<ChargeRule>() {
            @Override
            public Predicate toPredicate(Root<ChargeRule> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> list = new ArrayList<Predicate>();

                list.add(cb.equal(root.get("isHistory"), isHistory));

                if (StringUtils.isNotNullAndEmpty(historyRentRuleId)) {
                    list.add(cb.equal(root.get("rentRuleId"), historyRentRuleId));
                }
                if (StringUtils.isNotNullAndEmpty(rentRuleId)) {
                    list.add(cb.like(root.get("rentRuleId"), "%" + rentRuleId + "%"));
                }

                Predicate[] p = new Predicate[list.size()];
                return cb.and(list.toArray(p));
            }
        };
    }

    protected PageRequest buildPageRequest(DataTableParameter dataTableParam,Class<T> entityClass){
        int iDisplayStart = dataTableParam.getiDisplayStart();
        int iDisplayLength = dataTableParam.getiDisplayLength();
        List<String> iSortColsName = dataTableParam.getiSortColsName();
        List<String> sSortDirs = dataTableParam.getsSortDirs();

        Sort sort = null;
        if(!ListUtils.isNullOrEmpty(iSortColsName)){
            validatorSortColumns(iSortColsName,entityClass);
            List<Order> orders = Lists.newArrayList();
            for(int i=0;i<iSortColsName.size();i++){
                String sortCol = iSortColsName.get(i);
                String dir = sSortDirs.get(i);
                orders.add(new Order(getDirectionByDirString(dir),sortCol));
            }
            sort = new Sort(orders);
        }
        return new PageRequest(iDisplayStart / iDisplayLength, iDisplayLength, sort);
    }

因爲經過之前封裝成DataTableParam之後,分頁以及排序的方法都是相同的。所以實際上我是把buildPageRequest(..)方法放在BaseService中的。PageRequest、Specification是Spring data jpa的東西,所以不介紹了。

發佈了31 篇原創文章 · 獲贊 22 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章