在此博客开始之前,我在项目中增加了国家列表http://localhost:8080/ssm/country/list.do#展示功能使用的是Datatables,在后端没有做分页,返回所有数据,前端插件Datatables完成了分页、排序、搜索功能。在数据量小的时候可以这么做,但是数据量大的时候就需要自己写分页和搜索了。

我们在这个博客中使用PageHelper完成分页。

Mybatis分页插件 - PageHelper

该插件目前支持以下数据库的物理分页:Oracle、Mysql、MariaDB、SQLite、Hsqldb、PostgreSQL、DB2、SqlServer(2005,2008)、Informix、H2、SqlServer2012。

PageHelper的使用文档

在现在的项目中引入Mybatis分页插件。

首先,使用Maven引入PageHelper的jar包。

pom.xml

<!-- Pagehelper -->
<dependency>
	<groupId>com.github.pagehelper</groupId>
	<artifactId>pagehelper</artifactId>
	<version>4.1.6</version>
</dependency>

接着,修改spring-mybatis的配置文件中的sqlSessionFactory。

spring-mybatis.xml

<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <!-- 自动扫描mapping.xml文件 -->
    <property name="mapperLocations" value="classpath:org/totoro/ssm/mapping/*.xml"></property>
    <property name="typeAliasesPackage" value="org.totoro.ssm.model"/>
	<property name="plugins">
		<array>
			<bean class="com.github.pagehelper.PageHelper">
				<property name="properties">
					<value>
						reasonable=true
					</value>
				</property>
			</bean>
		</array>
	</property>
</bean>

最后,在service中调用:

CountryServiceImpl.java

public ArrayList<Country> pageList() {
	PageHelper.startPage(2, 4);
	return countryDao.list();  
}

这里使用的静态方法PageHelper.startPage调用,紧跟在这个方法后的第一个Mybatis查询方法会被进行分页。

这时PageHelper就引入到项目中了。

现在增加一个按照搜索、排序、页面参数查找国家的函数。

先增加查询sql:

CountryMapper.xml

  <select id="searchAndSort" resultMap="BaseResultMap" >
    select 'true' as QUERYID,
    <include refid="Base_Column_List" />
    from country
    <if test="search != null  and search !=''">
    where country_id like CONCAT('%','${search}','%' ) or country like CONCAT('%','${search}','%' )
    </if>
    order by ${colIndex} ${sortDirection}
  </select>

CountryMapper.java

ArrayList<Country> searchAndSort(@Param("search")String search, @Param("colIndex")String colIndex, @Param("sortDirection")String sortDirection);

再增加service层的调用: ICountryService.java

	/**
	 * 
	 * @Title: pageList
	 * @Description: 查找单位并排序
	 * @param: @param pageStart       页面序号
	 * @param: @param pageLength      页面大小
	 * @param: @param search          搜索词
	 * @param: @param colIndex        排序字段
	 * @param: @param sortDirection   排序方式
	 * @param: @return    参数                      结果分页
	 */
	public PageInfo<Country> pageList(Integer pageStart, Integer pageLength, String search, String colIndex, String sortDirection);

实现如下:

CountryServiceImpl.java

	@Override
	public PageInfo<Country> pageList(Integer pageStart, Integer pageLength, String search, String colIndex, String sortDirection) {
		int column = 0;
		if (colIndex != null) {
			column = Integer.parseInt(colIndex);
			if (column < 0 || column > 5)
				column = 0;
		}
		String colName = columnNames[column];
		PageHelper.startPage(pageStart, pageLength);
		ArrayList<Country> countryList = countryDao.searchAndSort(search,colName,sortDirection);
		PageInfo<Country> page = new PageInfo<Country>(countryList);
		return page; 
	}

最后在controller中增加:

CountryController.java

	@GET
	@RequestMapping("/datatable")
	@ResponseBody
	public JSONObject counttryDatatables(HttpServletRequest request,Model model){
		String displayStart = request.getParameter("iDisplayStart");
		String displayLength = request.getParameter("iDisplayLength");
		String search = request.getParameter("sSearch");
		String colIndex = request.getParameter("iSortCol_0");
		String sortDirection = request.getParameter("sSortDir_0");
		Integer pageLength = Integer.parseInt(displayLength);
		Integer pageStart = Integer.parseInt(displayStart)/pageLength + 1;
		PageInfo<Country> countryPageInfo = countryService.pageList(pageStart,pageLength,search,colIndex,sortDirection);
		
		JSONObject result = new JSONObject();
		result.put("iTotalRecords", countryPageInfo.getTotal());
		result.put("aaData", countryPageInfo.getList());
		result.put("iTotalDisplayRecords", countryPageInfo.getTotal());
		return result;
	}

以待使用。其中iDisplayStart当前展示开始记录序号、iDisplayLength每页展示条数、sSearch搜索词、iSortCol_0排序字段编号、sSortDir_0排序类型、iTotalRecords记录总条数、aaData返回数据集、iTotalDisplayRecords当前展示记录数,是准备给datatables使用的。下面开始介绍Datatables服务器处理。

Datatables服务器处理

现在Data Tables一次性获取所有数据,当数据量比较小的时候,这时是很高效的。当数据量比较大的时候,Datatables就会比较慢,这时因为渲染和创建dt、tr、td要花费时间。为了解决这个问题Datatables提供了服务器模式,把本来客户端所做的事情交给服务器去处理,比如 排序,分页,过滤。对于客户端来说这些操作都是比较消耗资源的, 所以打开服务器模式后有再多的数据也不用怕了。

当你打开服务器模式的时候,每次绘制表格的时候,Datatables会给服务器发送一个请求(包括当前分页,排序,搜索等等)。Datatables会发向 服务器发送大量的变量去执行所需要的处理,然后在服务器拼好相应的数据返回给Datatables。

我们在country/list.jsp的基础上进行修改,删除tbody部分,开启服务器模式需要使用serverSideprocessingsAjaxSourcecolumns

最后配置如下:

CountryController.java

$(function () {
	$("#example1").DataTable({
		//汉化

	    language: {
	        "sProcessing": "处理中...",
	        "sLengthMenu": "显示 _MENU_ 项结果",
	        "sZeroRecords": "没有匹配结果",
	        "sInfo": "显示第 _START_ 至 _END_ 项结果,共 _TOTAL_ 项",
	        "sInfoEmpty": "显示第 0 至 0 项结果,共 0 项",
	        "sInfoFiltered": "(由 _MAX_ 项结果过滤)",
	        "sInfoPostFix": "",
	        "sSearch": "搜索:",
	        "sUrl": "",
	        "sEmptyTable": "暂无信息",
	        "sLoadingRecords": "载入中...",
	        "sInfoThousands": ",",
	        "oPaginate": {
	            "sFirst": "首页",
	            "sPrevious": "上页",
	            "sNext": "下页",
	            "sLast": "末页"
	        },
	        "oAria": {
	            "sSortAscending": ": 以升序排列此列",
	            "sSortDescending": ": 以降序排列此列"
	        }
	    },
		//详细分页组,可以支持直接跳转到某页

	    "pagingType": "full_numbers",
	    //每页显示多少条选择

	    "lengthMenu": [ [ 5, 10, 25, 50, 75, 100, -1 ], [ 5, 10, 25, 50, 75, 100, "所有" ] ],
	    //默认显示条数

	    "displayLength": 10,
	    //默认排序行与排序方式

	    "order": [[ 1, "asc" ]],
	    //不排序的列的class

	    "columnDefs": [ {
	        "targets": 'nosort',
	        "orderable": false
	      } ],
	    //开启服务端处理

	    "processing": true,
	    "bServerSide": true,
	    "sAjaxSource" : "${ctx}/country/datatable.do",
        "columns": [
                    { "data": "countryId" },
                    { "data": "country" },
                    //展示时间

                    {
						"data": "lastUpdate",
						"render": function (data) {
					        var date = new Date(data);
					        var month = date.getMonth() + 1;
					        return (month.length > 1 ? month : "0" + month) + "/" + date.getDate() + "/" + date.getFullYear();
					    }
					},
					//展示传参按钮

                    { 
						"data": "countryId",
						"render": function (data) {
					        return "<a class='blue' href='javascript:void(0);' onclick='alert(" + data + ")' title='查看'>"
							+ "<i class='fa fa-fw fa-chrome '></i>"
							+ "</a>";
					    }
                    },
					//展示固定信息

                    { 
						"data": null,
						"defaultContent": "<a class='blue' href='javascript:void(0);' title='查看'>"
										+ "<i class='fa fa-fw fa-chrome '></i>"
										+ "</a>"
                    }
                ]
	});
});

然后访问http://localhost:8080/ssm/country/page_list.do就可以了。

碎碎念

  1. 修改了侧边栏,但是没有做定位和自动生成。

  2. datatables的可选参数很多,可以去官网看,也可以在这里查询,总结的比较全。可以再增加每个列的搜索、搜索的模糊匹配等功能,暂时这个项目中先不做了。

  3. 有两个不错的datatables的Demo,一个是DataTables –Serverside Processing,做了一个比较通用DataTables响应例子,参数很全。还有一个是Datatable Server Side Processing Using Java,在评论区有项目源码地址,还有一个youtube上的视频

  4. 源码参考

  5. 暂且先写到这里吧,Mybatis通用Mapper3、Tomcat连接池、Spring-Security、plupload、EasyMock、Memcached/Redis、Lucene/Solr先放一放,可能要等一段时间再添加了。