分页页面的数据,主要由两部分组成
当前页的结果集数据,比如这一页有哪些信息。
分页条信息,比如包含【首页】【上页】【下页】【末页】等
分页需要依赖的变量 :
beginPage =1首页 prevPage 上一页 nextPage下一页 totalPage 总页数/末页 totalCount 总条数
currentPage 当前页 pageSize 每页显示多少条数据 当前页的数据 result
数据的来源:
需要用户传入的两个数据
int currentPage = 1; 当前页,跳转到第几页
int pageSize = 10; 每页最多多少条数据
需要两条SQL查询出来的数据
int totalCount; 数据总条数
List result; 每一页的结果集数据
自己计算出来的三个值
int prevPage :上一页
int nextPage :下一页
int totalPage :总页数/末页
计算方式:
int totalPage = rows % pageSize == 0 ? rows / pageSize : rows / pageSize + 1; (优先计算)
int prevPage = currentPage > 1 ? currentPage - 1 : 1;
int nextPage = currentPage < totalPage ? currentPage + 1 : totalPage
通过SQL查询出来数据总条数和每一页的结果集数据
第一条SQL:查询符合条件的结果总数(totalCount)
SELECT COUNT(*) FROM 表名 [WHERE 条件]
第二条SQL:查询符合条件的结果集(result)
SELECT * FROM 表名 [WHERE 条件] LIMIT ?,?;
第一个?:从哪一个索引的数据开始截取(从0开始) beginIndex = (currentPage - 1) * pageSize
第二个?:pageSize 每页多少条数据
把分页查询的结果对象封装在page包中方便管理
/**
* 用来封装分页数据
*/
@Getter
@ToString
public class PageResult {
// 两个用户输入
private int currentPage; // 当前页码
private int pageSize; // 分页显示的最大记录数
// 两个SQL的执行结果
private int totalCount; // 总记录数
private List<?> result; // 当前页数的数据
// 三个计算结果
private int totalPage; //总页数,尾页码
private int prevPage; // 上一页
private int nextPage; // 下一页
public PageResult(int currentPage, int pageSize) {
this(currentPage,pageSize,0,new ArrayList<>());
}
public PageResult(int currentPage, int pageSize, int totalCount, List<?> result) {
this.currentPage = currentPage;
this.pageSize = pageSize;
this.totalCount = totalCount;
this.result = result;
// 计算
this.totalPage = totalCount % pageSize == 0 ? totalCount / pageSize : totalCount / pageSize + 1;
this.prevPage = currentPage - 1 > 1 ? currentPage - 1 : 1;
this.nextPage = currentPage + 1 < totalCount ? currentPage + 1 : totalPage;
}
}
需要在DAO组件增加两个方法
int queryForCount(int currentPage, int pageSize); List> queryForList(int currentPage, int pageSize);
但是在MyBatis提供的操作方法传入执行SQL任务的参数对象只能是一个对象所以要把前台传递过来的两个值封装
/**
* 封装每页操作,前台用户传来的数据
*/
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class QueryObject {
// 分页依赖的两个数据
private int currentPage = 1; // 当前页
private int pageSize = 3; // 每页显示条数
/**
* 返回每页开始的数据的索引
* limit #{beginIndex},#{pageSize}
*
* @return
*/
public int getBeginIndex() {
return (currentPage - 1) * pageSize;
}
}
此时的DAO中方法:
int queryForCount(QueryObject qo); List> queryForList(QueryObject qo);
准备工作:
定义PageResult类,用于封装分页查询后每页的所有数据(结果集和分页条信息),存放于query包中。
定义QueryObject类,用于封装分页查询前台用户传入数据,存放于query包中。
操作步骤:
在DAO接口中定义两个方法,分别用于查询结果总数和结果集。
在Mapper文件中编写分页查询的两条SQL语句,在DAO实现类中执行查询操作。
Mapper文件:
<select id="queryForList" resultType="cn.wolfcode.emis.daomain.Employee">
select * from employeelimit #{beginIndex},#{pageSize}
select>
<select id="queryForCount" resultType="int">
select count(id) from employee
select>
DAO实现类:
public List<Employee> queryForList(EmployeeQueryObject qo) {
SqlSession sqlSession = MyBatisUtil.openSession();
List<Employee> list = sqlSession.selectList("cn.wolfcode.emis.mapper.EmployeeMapper.queryForList",qo);
sqlSession.commit();
sqlSession.close();
return list;
}
public int queryForCount(EmployeeQueryObject qo) {
SqlSession sqlSession = MyBatisUtil.openSession();
int selectOne = sqlSession.selectOne("cn.wolfcode.emis.mapper.EmployeeMapper.queryForCount", qo);
sqlSession.commit();
sqlSession.close();
return selectOne;
}
在service接口中增强分页查询方法,并在service实现类中实现。
service实现类:
public PageResult query(EmployeeQueryObject qo) {
IEmployeeDAO emp = new EmployeeDAOImpl();
// 通过DAO获取总记录数
int totalCount = emp.queryForCount(qo);
// 判断是是否有数据,有返回查询到的数据,没有返回一个空集合
if (totalCount < 1){
return new PageResult(qo.getCurrentPage(),qo.getPageSize());
}
int pageSize = qo.getPageSize();
int totalPage = totalCount % pageSize == 0 ? totalCount / pageSize : totalCount / pageSize + 1;
if (qo.getCurrentPage() > totalPage) {
qo.setCurrentPage(totalPage);
}
if (qo.getCurrentPage() < 1){
qo.setCurrentPage(1);
}
List<Employee> list = emp.queryForList(qo);
return new PageResult(qo.getCurrentPage(),qo.getPageSize(),totalCount,list);
}
操作步骤:
必须先完成业务层组件,保证后台测试通过
根据MVC思想,浏览器发出分页请求参数( 去往第几页 / 每页多少条数据)
在Servlet中接收currentPage参数,并封装到QueryObject对象,调用service中分页查询方法(query)
把得到的分页查询结果对象(PageResult)共享在请求作用域中,跳转到JSP,显示即可
修改JSP页面,编写出分页条信息(分页条中的信息来源于PageResult对象)
代码:
Servlet:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
EmployeeQueryObject qo = new EmployeeQueryObject();
req2qo(req, qo);
PageResult pageResult = service.query(qo);
req.setAttribute("PageResult", pageResult);
req.getRequestDispatcher("/WEB-INF/view/list.jsp").forward(req, resp);
}
private void req2qo(HttpServletRequest req, EmployeeQueryObject qo) {
String currentPage = req.getParameter("currentPage");
if (StringUtil.hashLength(currentPage)) {
qo.setCurrentPage(Integer.valueOf(currentPage));
req.setAttribute("currentPage", qo.getCurrentPage());
}
String pagesize = req.getParameter("pageSize");
if (StringUtil.hashLength(pagesize)) {
qo.setPageSize(Integer.valueOf(pagesize));
req.setAttribute("pageSize", qo.getPageSize());
}
}
list.jsp:
高级查询,就是多条件过滤,根据多个查询条件去筛选结果集。如,在商品列表中,用户可以根据自己的需要,按照商品的名称或者价格范围对商品进行查询。
阅读MyBatis官方文档,搞明白 if 和 where两个元素是用来干什么的,有什么作用。
if元素,用于判断,一般用作是否应该符合某一个查询条件
<if test="boolean表达式">if>
where元素,只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。where 和 if的配合使用案例
<select id="query" resultType="Product">
SELECT * FROM product
<where>
<if test="minPrice !=null">
AND salePrice >= #{minPrice }
if>
<if test="maxPrice !=null">
AND salePrice <= #{maxPrice }
if>
where>
select>
/**
* 封装员工的过滤查询和分页查询的条件
*/
@Setter
@Getter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class EmployeeQueryObject extends QueryObject {
// 过滤查询需要的条件
private String name;
private BigDecimal minSalary;
private BigDecimal maxSalary;
}
QueryObect是其他查询对象的父类,可以在该类中封装查询对象的相同成员
操作步骤:
修改list.jsp页面,增加高级查询表单,包含需要查询的信息,注意:让该表单(form)包含列表的table元素。
在query包中定义EmployeeQueryObject类,继承于QueryObject,该类用于封装货品对象的高级查询信息。注意:一般的,为了避免不必要的麻烦,让字段名称和表单中的请求参数名称相同。
在Servlet中调用query方法之前,接受高级查询数据,并封装到EmployeeQueryObject对象中。
重新回去修改list.jsp页面,使之支持回显出查询的信息。在元素中,value属性表示该文本框中显示什么数据。
在productMapper.xml中拼写查询的SQL语句,查询结果总数和查询结果集都要拼写,且查询条件是一样的。
<select id="queryForList" resultType="cn.wolfcode.emis.daomain.Employee">
select * from employee
<where>
<if test="name != null and name != ''">
AND name like concat('%',#{name},'%')
if>
<if test="minSalary">
and salary >= #{minSalary}
if>
<if test="maxSalary">
and salary <= #{maxSalary}
if>
where>
limit #{beginIndex},#{pageSize}
select>
<select id="queryForCount" resultType="int">
select count(id) from employee
<where>
<if test="name != null and name != ''">
AND name like concat('%',#{name},'%')
if>
<if test="minSalary">
and salary >= #{minSalary}
if>
<if test="maxSalary">
and salary <= #{maxSalary}
if>
where>
select>
解决方案: