我是如何作列表頁的

  最近可貴公司業務稍微緩解一些,咱們終於有時間靜下心總結下技術,對於以前的項目去其糟粕取其精華,咱們的目的是:前端

  • 解決後臺管理系統的開發效率問題,封裝經常使用功能,將技術性強的內容分離出去;
  • 將重複性高的開發工做統一技術規範,避免各自研究;
  • 採用最佳實踐,參考優秀項目,制定最佳方法,至少是最適合當前團隊的。

  這裏我先總結下我這塊針對數據列表頁的作法,後續再補充其它模塊的作法,先看下列表頁的需求:java

  • 搜索條件支持動態條件查詢,後端不須要干預相關條件的組裝;即不能出現相似以下的代碼(注:此作法只針對單表的查詢,若是是很是複雜的多表關聯,此方案也許不是最佳的)
       if(!StringUtils.isEmpty(employeeEnityRequest.getEmployeeName())){
            criteria.andEmployeeNameEqualTo(employeeEnityRequest.getEmployeeName());
        }
        if(!StringUtils.isEmpty(employeeEnityRequest.getEmployeeStatus())){
            criteria.andEmployeeStatusEqualTo(Integer.valueOf(employeeEnityRequest.getEmployeeStatus()));
        }

 

  • 查詢異步,用戶點擊下一頁時若是須要刷新整個頁面體驗性不太好。

  上面這兩需求很是常規,有不少種實現方式,我分享下個人作法(個人環境是eclipse,tomcat,maven,spring mvc, mybatise,mysql):mysql

  針對動態查詢,咱們經過約定規則來實現,好比View中咱們能夠這樣寫jquery

<input type="text" name="WHERE.storeName.LIKE"    class="form-control" style="width: 180px;" " />

 

  它的意思是查詢email字段,操做符是=號。WHERE是固定的,後臺解析收集條件時作識別做用,中間的是字段名稱,後面是操做符,操做符好比有EQ,LIKE等常規的數據庫查詢操做符。這樣咱們能夠在前端任意增長修改條件,然後臺的邏輯是不須要有任務變動的,詳細的收集過程請看本文後面的介紹。

  針對異步查詢,我採用了angularjs相關技術,當時遇到一個問題:angularjs在查詢時通常都會指定一個寫好的model傳遞到後臺,但因爲上面動態查詢的條件是變更的(字段名稱不固定,字段數量不固定,操做類型不固定),因此沒有辦法去定義這樣的model。第一直覺是將整個表單傳遞到後臺,後臺根據表單的值來解決特定的條件,第二個問題來了,既然是將表單傳遞到後臺,那麼後臺要用什麼參數來接收這個表單呢,於時想到HttpServletRequest,但通過測試,這個參數始終取不到值,當時的代碼以下:
  javaangularjs

    @RequestMapping(value = "/getStoreByPage", method = RequestMethod.POST)
    @ResponseBody
    public PageInfo<BcStore> getStoreByPage(HttpServletRequest request,int pageNum, int pageSize) {

   jsajax

$.ajax({
    type : "POST",
    url : url,
    dataType : 'json',
    data:$("#searchForm").serialize(),
    async : false,
    success : function(data) {
        $scopeLocal.pageResponse = data;
        $scopeLocal.content=data.list;
    }
});


  後來和同事討論說是須要設置ajax的contentType爲application/x-www-form-urlencoded,但設置後直接報錯,請求沒法到達服務端,說明參數類型匹配錯誤,將後臺controller方法中的參數HttpServletRequest刪除後順利經過。但這個參數刪除了,表單值從哪取呢?好在後端也能夠取到當前請求,RequestContextHolder能夠幫助咱們,因而下面的代碼就水到渠成了,經過這個幫助類咱們能夠從請求中根據咱們制定的規定來解析條件,至於條件對象的格式,主要看數據訪問端的使用狀況,這裏先不貼代碼了,咱們主要採用的是通用mapper那套方案,網上可去搜索。到此,問題解決了,數據也能夠順利查到了。spring

private static String DEFAULT_PRE_WHERE = "WHERE.";
private String preWhere = DEFAULT_PRE_WHERE;
List<String> searchFilterStrings = Lists.newArrayList();

        Map<String, String[]> map = request.getParameterMap();

        for (Map.Entry<String, String[]> entry : map.entrySet()) {
            String strKey = entry.getKey();
            for (String value : entry.getValue()) {

                if (!Strings.isNullOrEmpty(value)
                        && !"none".equals(value)
                        && strKey.startsWith(preWhere)) {

                    String filedAndOp = strKey.substring(preWhere.length());
                    searchFilterStrings.add(String.format("%s.%s", filedAndOp, value));
                }
            }
        }


  列表數據的展現,我沒有采用jquery datatable之類的控件,我感受須要寫JS代碼,看起來比較複雜,採用angularjs的ng-repeat很是直觀,且容易控制細節。sql

<table id="datatable1" cellpadding="0" cellspacing="0" border="0"
                                class="datatable table table-striped table-bordered table-hover">
                                <thead>
                                    <tr>
                                        <th>門店編號</th>
                                        <th>名稱</th>
                                        <th>類型</th>
                                        <th>店長</th>
                                        <th>電話</th>
                                        <th>郵箱</th>
                                        <th>狀態</th>
                                        <th>建立時間</th>
                                        <th>操做</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <tr ng-repeat="store in content">
                                        <td>{{store.storeCode}}</td>
                                        <td>{{store.storeName}}</td>
                                        <td>
                                            <div ng-show="store.storeType=='1'">
                                                <span class="label label-success">自營店</span>
                                            </div>
                                            <div ng-show="store.storeType=='0'">
                                                <span class="label label-danger">加盟店</span>
                                            </div>
                                        </td>


  分頁控制咱們採用了angularjs與boostrap的一個插件完成,須要引用ui-bootstrap-tpls.min.js以及boostrap-ui相關的代碼才行:數據庫

 <pagination class="pagination-sm"
                                        ng-model="pageRequest.pageNum"
                                        total-items="pageResponse.total"
                                        max-size="4"
                                        ng-change="pageRequest.getResponse()"
                                        items-per-page="pageRequest.pageSize"
                                        rotate="false"
                                        previous-text="上一頁" next-text="下一頁"
                                        ></pagination>


  js代碼,爲了使前端調用方式,咱們儘可能作了封裝,使得查詢邏輯只須要寫最少的代碼:注入一個$listService,而後傳一個請求地址給它就能夠了,固然這裏面有些固定寫法,好比一個request對象的屬性,須要先後臺配置一塊兒完成才行,不能隨意寫。json

var mainApp = angular.module('storeManageApp',['ui.bootstrap']); 
     $.initListService(mainApp);
     mainApp.controller('storeManageCtrl', function ($scope, $http,$listService) {
                var listUrl="<c:url value="/store/getAllByPage"/>";
                $listService.init($scope,listUrl);
                $listService.get();
                
            });

 angularjs的注入作的不錯,咱們封裝的js也參考了angularjs提供的service模式來完成:因爲這個service是須要angular對象的,因此作了一個jquery的擴展函數,便於調用,函數裏面的代碼就比較簡單的,常規的service寫法,這裏指出下,ajax提交後臺的參數我沒有采用data參數,而是直接拼接在url上,若是放在data上應該加了那個contentType。

jQuery.extend({
    initListService: function(mainApp) {
        mainApp.service('$listService', function(){    
              var $scopeLocal={};
              this.init = function($scope,listUrl) { 
                  $scopeLocal=$scope;
                  $scopeLocal.pageRequest = {
                        "pageNum": 1, "pageSize": "5"
                     };
                  $scopeLocal.pageRequest.getResponse = function () {
                     var requestData = $("#searchForm").serialize();
                     var url = listUrl+"?"+requestData+"&pageNum="+$scopeLocal.pageRequest.pageNum;
                     $.ajax({
                         type : "POST",
                         url : url,
                         dataType : 'json',
                         async : false,
                         success : function(data) {
                             $scopeLocal.pageResponse = data;
                             $scopeLocal.content=data.list;
                         }
                     });
                 
                 }
                 this.get = function() { 
                     $scopeLocal.pageRequest.getResponse();
                 };
                
              
           }
        });
    }
});

 

  最後上一個列表頁的效果圖:

 
  

  功能看起來不錯,但還有一些不完善的,好比應該提供幾個數據加載事件便於在數據加載先後作些特殊的處理操做。可是一個好的開始,後續團隊成員只要參考這個模板來作效率上會提高一部分,固然提高效率不光是這篇文章中介紹的,咱們還有權限過濾的集成,各種控件的封裝等等功能。

相關文章
相關標籤/搜索