您的位置:首页 > Web前端 > AngularJS

AngularJs+Spring MVC实现分页小结

2017-08-10 10:00 363 查看
我是AngualrJs菜鸟,所以特别感谢大神用AngularJs创建自己的Grid–分页组件 tm.pagination.js,帮我实现了这篇博客中最核心的部分。我主要写一下一些细节过程[[大神开源代码地址请戳我]]

大概实现效果是这样的:



前端代码是这样子的:

<!doctype html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/king/resources/bootstrap-3.3.7/css/bootstrap.min.css">
<script src="/king/resources/angular-1.6.4/angular-1.6.4/angular.min.js"></script>
<script src="/king/resources/pagination/tm.pagination.js"></script>
<style>
.page-list .pagination {float:left;}
.page-list .pagination span {cursor: pointer;}
.page-list .pagination .separate span{cursor: default; border-top:none;border-bottom:none;}
.page-list .pagination .separate span:hover {background: none;}
.page-list .page-total {float:left; margin: 25px 20px;}
.page-list .page-total input, .page-list .page-total select{height: 26px; border: 1px solid #ddd;}
.page-list .page-total input {width: 40px; padding-left:3px;}
.page-list .page-total select {width: 50px;}
</style>
</head>

<body ng-controller="testController">
<div>
<div class="container">
<div class="row" >
<h1>查询列表页</h1>
<div class="col-lg-3">
<p class="lead">ID:</p>
<input type="text" class="form-control " ng-model="User.id">
</div>
<div class="col-lg-3">
<p class="lead">Name:</p>
<input type="text" class="form-control " ng-model="User.username">
</div>
<div class="col-lg-3">
<p class="lead">Age:</p>
<input type="text" class="form-control " ng-model="User.password">
</div>
<div class="col-lg-3">
<button class="btn btn-default" ng-click="queryUser()">查询</button>
</div>
</div>
<br><br>
<table class="table" >
<thead>
<tr>
<td class="active">ID</td>
<td class="success">USERNAME</td>
<td class="warning">PASSWORD</td>
<td class="danger">其他的</td>
<td class="success">操作</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in Users">
<td class="active">{{x.id}}</td>
<td class="success">{{x.username}}</td>
<td class="warning">{{x.password}}</td>
<td class="danger">{{x.username}}</td>
<td class="success" ng-click="deleteThis()"> 删除</td>
</tr>
</tbody>
</table>
<tm-pagination conf="paginationConf"></tm-pagination>
</div>
</div>
<!-- <button class="btn btn-default" ng-click="reGetProducts()">请求</button> -->

<script>
angular.module('myApp', ['tm.pagination']).controller('testController', function($scope, $http){

// 配置分页基本参数
$scope.paginationConf = {
currentPage: 1,
itemsPerPage: 10,
perPageOptions: [10, 20, 24, 30, 40, 50,100]
};
//第一次进来取count和data
$http.post("http://localhost:8080/king/userController/both").then(function(result){
$scope.paginationConf.totalItems=result.data.count;
$scope.Users = result.data.data;
});

// 分页时候触发 获取数据条目
var reGetUsers = function(){
// 发送给后台的请求数据
//每页条数
var max= $scope.paginationConf.itemsPerPage;
//偏移量
var offset= ($scope.paginationConf.currentPage-1)*max;

$scope.User={
offset : offset,
max : max
};
$http({
method: 'POST',
params: $scope.User,
url: 'http://localhost:8080/king/userController/both'
}).then(function(result){
// 变更产品条目
$scope.Users = result.data.data;
});
};

// 通过$watch currentPage和itemperPage 当他们一变化的时候,重新获取数据条目
$scope.$watch('paginationConf.currentPage + paginationConf.itemsPerPage', reGetUsers);
//查询触发
$scope.queryUser = function(){
$http({
method: 'POST',
params: $scope.User,
url: 'http://localhost:8080/king/userController/both'
}).then(function (result) {  //正确请求成功时处理
$scope.paginationConf.totalItems=result.data.count;
$scope.Users = result.data.data;
}).catch(function (result) { //捕捉错误处理
alert(result.data.Message);
});
};

})
</script>
</body>
</html>


首先为了项目考虑,前端只能用html,这导致了第一个问题,Spring MVC配置无法访问静态的html文件。我是这么解决的:

<!-- 在web.xml中加入下面代码,表示对 下列静态资源不拦截。 -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>


注意:上面这段代码必须写在DispatcherServlet前面,表示不用你管我。

现在可以访问到我们的页面了,第二个问题出现了:

@RequestMapping(value="/display")
public ModelAndView toExitPage(HttpServletRequest request,
HttpServletResponse response)throws Exception{
Map<String, Object> model = new HashMap<String, Object>();
return new ModelAndView("AngularJs/newpagination",model);
}


通过RequestMapping注解配置找到这里,ModelAndView只返回了视图,并没有携带数据。因为html是静态的,无法通过el表达式接收${数据}。所以我只好加载完页面后,立即ajax异步请求一次。就是这一段代码的作用:

$http.post("http://localhost:8080/king/userController/both").then(function(result){
$scope.paginationConf.totalItems=result.data.count;
$scope.Users = result.data.data;
});


那么后台Controller里是怎么写的呢?

@RequestMapping(value="/both", method={RequestMethod.POST,RequestMethod.GET})
@ResponseBody
public Map<String, Object> queryBoth(User user, HttpServletRequest request) {
List<User> list = new ArrayList<User>();
list = userService.getByUser(user);
Map<String, Object> model=new HashMap<String, Object>();
model.put("data", list);
user.setMax(null);
Integer totalItems=userService.getByUser(user).size();
model.put("count", totalItems);
return model;
}


这段代码主要做了两件事,一是取要展示的数据,存进list,二是计算数据总量(给分页框架用)。可能会有人说,totalItems取list.size()不就可以了。是不可以的,因为list是分页查询的,它的size最多为每页的条数,这就是为什么要user.setMax(null)。剩下的就是AngualrJs在前端取数据应用和展示了,前面代码里写的很清楚,就不说了。

基本的流程操作完成了,说一下大神框架的应用细节。

1 需要显示的配置分页基本参数,可以把这一段封装在tm.pagination.js文件里。

// 配置分页基本参数
$scope.paginationConf = {
currentPage: 1,
itemsPerPage: 10,
perPageOptions: [10, 20, 24, 30, 40, 50,100]
};


link: function(scope, element, attrs) {

// 封装进来 配置分页基本参数
scope.conf = {
currentPage: 1,
itemsPerPage: 10,
perPageOptions: [10, 20, 24, 30, 40, 50,100]
};
var conf = scope.conf;


2 不太懂的地方,为什么点击分页的时候,会监测到paginationConf.currentPage、paginationConf.itemsPerPage这两个参数发生变化,tm.pagination.js里的代码是怎么和这两个参数对应起来的。

下午回来自答一波:因为用了双向绑定。

<tm-pagination conf="paginationConf"></tm-pagination>

angular.module('tm.pagination', []).directive('tmPagination',[function(){
return {
/*
1.restrict
(字符串)可选参数,指明指令在DOM里面以什么形式被声明;取值有:
E(元素),A(属性),C(类),M(注释),其中默认值为A;
当然也可以两个一起用,比如EA.表示即可以是元素也可以是属性。
*/
restrict: 'EA',
/*
* template(字符串或者函数)可选参数,可以是:
(1)一段HTML文本
(2)一个函数,可接受两个参数tElement和tAttrs
*/
template: '<div class="page-list">' +
'<ul class="pagination" ng-show="conf.totalItems > 0">' +
'<li ng-class="{disabled: conf.currentPage == 1}" ng-click="prevPage()"><span>«</span></li>' +
'<li ng-repeat="item in pageList track by $index" ng-class="{active: item == conf.currentPage, separate: item == \'...\'}" ' +
'ng-click="changeCurrentPage(item)">' +
'<span>{{ item }}</span>' +
'</li>' +
'<li ng-class="{disabled: conf.currentPage == conf.numberOfPages}" ng-click="nextPage()"><span>»</span></li>' +
'</ul>' +
'<div class="page-total" ng-show="conf.totalItems > 0">' +
'每页<select ng-model="conf.itemsPerPage" ng-options="option for option in conf.perPageOptions " ng-change="changeItemsPerPage()"></select>' +
'/共<strong>{{ conf.totalItems }}</strong>条 ' +
'跳转至<input type="text" ng-model="jumpPageNum" ng-keyup="jumpPageKeyUp($event)"/>页' +
'</div>' +
'<div class="no-items" ng-show="conf.totalItems <= 0">暂无数据</div>' +
'</div>',
replace: true,
/*
* 布尔值或者对象,可选参数,默认值为false,表示继承父级作用域。
* 如果值为true,表示继承父作用域,并创建自己的作用域(子作用域)
* 如果为对象,{},则表示创建一个全新的隔离作用域。
* 当我们将scope的值设置为{}时,没办法从父级作用域中继承到color的值了。
*/
scope: {
//使用'='进行双向绑定 (使用@来进行单向文本(字符串)绑定)
conf: '='
},


// 通过$watch currentPage和itemperPage 当他们一变化的时候,重新获取数据条目
$scope.$watch('paginationConf.currentPage + paginationConf.itemsPerPage', reGetUsers);


3 reGetUsers函数,要自己显示的计算max和offset。太low了,是自己的代码能力问题,肯定能封装一下的。

4 点击查询的时候,函数代码和reGetUsers函数是一样的,但是我还没学会在AngularJs中怎么复用函数。

总结:虽然算是成功了,但是有许多细节上的问题可以优化,希望各路大神指出不足之处和可以改进的地方。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息