日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

我是如何做列表頁(yè)的

 昵稱10504424 2016-01-13

  最近難得公司業(yè)務(wù)稍微緩解一些,我們終于有時(shí)間靜下心總結(jié)下技術(shù),對(duì)于之前的項(xiàng)目去其糟粕取其精華,我們的目的是:

  • 解決后臺(tái)管理系統(tǒng)的開(kāi)發(fā)效率問(wèn)題,封裝常用功能,將技術(shù)性強(qiáng)的內(nèi)容分離出去;
  • 將重復(fù)性高的開(kāi)發(fā)工作統(tǒng)一技術(shù)規(guī)范,避免各自研究;
  • 采用最佳實(shí)踐,參考優(yōu)秀項(xiàng)目,制定最佳方法,至少是最適合當(dāng)前團(tuán)隊(duì)的。

  這里我先總結(jié)下我這塊針對(duì)數(shù)據(jù)列表頁(yè)的做法,后續(xù)再補(bǔ)充其它模塊的做法,先看下列表頁(yè)的需求:

  • 搜索條件支持動(dòng)態(tài)條件查詢,后端不需要干預(yù)相關(guān)條件的組裝;即不能出現(xiàn)類似如下的代碼(注:此做法只針對(duì)單表的查詢,如果是非常復(fù)雜的多表關(guān)聯(lián),此方案也許不是最佳的)
       if(!StringUtils.isEmpty(employeeEnityRequest.getEmployeeName())){
            criteria.andEmployeeNameEqualTo(employeeEnityRequest.getEmployeeName());
        }
        if(!StringUtils.isEmpty(employeeEnityRequest.getEmployeeStatus())){
            criteria.andEmployeeStatusEqualTo(Integer.valueOf(employeeEnityRequest.getEmployeeStatus()));
        }

 

  • 查詢異步,用戶點(diǎn)擊下一頁(yè)時(shí)如果需要刷新整個(gè)頁(yè)面體驗(yàn)性不太好。

  上面這兩需求非常常規(guī),有很多種實(shí)現(xiàn)方式,我分享下我的做法(我的環(huán)境是eclipse,tomcat,maven,spring mvc, mybatise,mysql):

  針對(duì)動(dòng)態(tài)查詢,我們通過(guò)約定規(guī)則來(lái)實(shí)現(xiàn),比如View中我們可以這樣寫(xiě)

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

 

  它的意思是查詢email字段,操作符是=號(hào)。WHERE是固定的,后臺(tái)解析收集條件時(shí)做識(shí)別作用,中間的是字段名稱,后面是操作符,操作符比如有EQ,LIKE等常規(guī)的數(shù)據(jù)庫(kù)查詢操作符。這樣我們可以在前端任意增加修改條件,而后臺(tái)的邏輯是不需要有任務(wù)變更的,詳細(xì)的收集過(guò)程請(qǐng)看本文后面的介紹。

  針對(duì)異步查詢,我采用了angularjs相關(guān)技術(shù),當(dāng)時(shí)遇到一個(gè)問(wèn)題:angularjs在查詢時(shí)一般都會(huì)指定一個(gè)寫(xiě)好的model傳遞到后臺(tái),但由于上面動(dòng)態(tài)查詢的條件是變動(dòng)的(字段名稱不固定,字段數(shù)量不固定,操作類型不固定),所以沒(méi)有辦法去定義這樣的model。第一直覺(jué)是將整個(gè)表單傳遞到后臺(tái),后臺(tái)根據(jù)表單的值來(lái)解決特定的條件,第二個(gè)問(wèn)題來(lái)了,既然是將表單傳遞到后臺(tái),那么后臺(tái)要用什么參數(shù)來(lái)接收這個(gè)表單呢,于時(shí)想到HttpServletRequest,但經(jīng)過(guò)測(cè)試,這個(gè)參數(shù)始終取不到值,當(dāng)時(shí)的代碼如下:
  java

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

   js

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


  后來(lái)和同事討論說(shuō)是需要設(shè)置ajax的contentType為application/x-www-form-urlencoded,但設(shè)置后直接報(bào)錯(cuò),請(qǐng)求無(wú)法到達(dá)服務(wù)端,說(shuō)明參數(shù)類型匹配錯(cuò)誤,將后臺(tái)controller方法中的參數(shù)HttpServletRequest刪除后順利通過(guò)。但這個(gè)參數(shù)刪除了,表單值從哪取呢?好在后端也可以取到當(dāng)前請(qǐng)求,RequestContextHolder可以幫助我們,于是下面的代碼就水到渠成了,通過(guò)這個(gè)幫助類我們可以從請(qǐng)求中根據(jù)我們制定的規(guī)定來(lái)解析條件,至于條件對(duì)象的格式,主要看數(shù)據(jù)訪問(wèn)端的使用情況,這里先不貼代碼了,我們主要采用的是通用mapper那套方案,網(wǎng)上可去搜索。到此,問(wèn)題解決了,數(shù)據(jù)也可以順利查到了。

復(fù)制代碼
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));
                }
            }
        }
復(fù)制代碼


  列表數(shù)據(jù)的展示,我沒(méi)有采用jquery datatable之類的控件,我感覺(jué)需要寫(xiě)JS代碼,看起來(lái)比較復(fù)雜,采用angularjs的ng-repeat非常直觀,且容易控制細(xì)節(jié)。

復(fù)制代碼
<table id="datatable1" cellpadding="0" cellspacing="0" border="0"
                                class="datatable table table-striped table-bordered table-hover">
                                <thead>
                                    <tr>
                                        <th>門(mén)店編號(hào)</th>
                                        <th>名稱</th>
                                        <th>類型</th>
                                        <th>店長(zhǎng)</th>
                                        <th>電話</th>
                                        <th>郵箱</th>
                                        <th>狀態(tài)</th>
                                        <th>創(chuàng)建時(shí)間</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">自營(yíng)店</span>
                                            </div>
                                            <div ng-show="store.storeType=='0'">
                                                <span class="label label-danger">加盟店</span>
                                            </div>
                                        </td>
復(fù)制代碼


  分頁(yè)控制我們采用了angularjs與boostrap的一個(gè)插件完成,需要引用ui-bootstrap-tpls.min.js以及boostrap-ui相關(guān)的代碼才行:

復(fù)制代碼
 <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="上一頁(yè)" next-text="下一頁(yè)"
                                        ></pagination>
復(fù)制代碼


  js代碼,為了使前端調(diào)用方式,我們盡量做了封裝,使得查詢邏輯只需要寫(xiě)最少的代碼:注入一個(gè)$listService,然后傳一個(gè)請(qǐng)求地址給它就可以了,當(dāng)然這里面有些固定寫(xiě)法,比如一個(gè)request對(duì)象的屬性,需要前后臺(tái)配置一起完成才行,不能隨意寫(xiě)。

復(fù)制代碼
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();
                
            });
復(fù)制代碼

 angularjs的注入做的不錯(cuò),我們封裝的js也參考了angularjs提供的service模式來(lái)完成:由于這個(gè)service是需要angular對(duì)象的,所以做了一個(gè)jquery的擴(kuò)展函數(shù),便于調(diào)用,函數(shù)里面的代碼就比較簡(jiǎn)單的,常規(guī)的service寫(xiě)法,這里指出下,ajax提交后臺(tái)的參數(shù)我沒(méi)有采用data參數(shù),而是直接拼接在url上,如果放在data上應(yīng)該加了那個(gè)contentType。

復(fù)制代碼
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();
                 };
                
              
           }
        });
    }
});
復(fù)制代碼

 

  最后上一個(gè)列表頁(yè)的效果圖:

 
  

  功能看起來(lái)不錯(cuò),但還有一些不完善的,比如應(yīng)該提供幾個(gè)數(shù)據(jù)加載事件便于在數(shù)據(jù)加載前后做些特殊的處理操作。但是一個(gè)好的開(kāi)始,后續(xù)團(tuán)隊(duì)成員只要參考這個(gè)模板來(lái)做效率上會(huì)提升一部分,當(dāng)然提升效率不光是這篇文章中介紹的,我們還有權(quán)限過(guò)濾的集成,各類控件的封裝等等功能。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多