目录
一、jstl标签。
(1)基本概念。
(2)使用前提。
(3)"<%...%>"与"<%=%>"。
(4)使用jstl标签的步骤。
1、导入对应jar包。
2、引入核心标签库。(core)
3、在jsp页面中使用jstl标签(常见标签)。
二、分页查询。
(1)使用循环拿对象,利用EL表达式显示属性。
(2)通过Bootstrap获取分页栏组件快速渲染页面(jsp)。
(3)分页查询思路分析。
1、页面(前端)需要传什么参数?
2、页面需要接收什么参数。
3、Page类。
4、sql语句的书写。
三、正式代码书写。
(1)链接到对应Servlet。
(2)queryUsersByPageServlet类。
(3)service层接口。
(4)serviceImpl实现类。
(5)dao层接口。(数据访问层接口)
(6)dao层实现类。
(7)初步测试其功能是否正常。
(8)完善设计要求。
1、当前所在页为:1。
2、当前所在页为:最后一页。
3、位于当前页时。
4、显示页数(如:1、2...)。
5、测试结果。
一、jstl标签。
(1)基本概念。
- JSTL(JavaServer Pages Standard Tag Library)是一个为JavaServerPages (JSP) 技术提供的标签库。
- 它允许开发者在JSP页面中使用标签来执行常见的功能。如条件判断、循环等。
(2)使用前提。
- 导入两个jar包。
- 或使用Maven添加对应的依赖也能够使用。
(3)"<%...%>"与"<%=%>"。
- 简单说:jsp页面就是让Java代码能够在html页面书写。
<% //java方法能写的代码, 都可以在这里写 %> <%=表达式 %> 把表达式的结果在客户端页面显示 使用EL表达式替换
(4)使用jstl标签的步骤。
1、导入对应jar包。
2、引入核心标签库。(core)
- 注意:"uri"一定要选择对应的正确核心库标签。
- 它也叫"c标签"。
- @tag:目标,lib:库。
<%--引入JSTL核心标签库--%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
3、在jsp页面中使用jstl标签(常见标签)。
- 循环:<c:forEach>。
- if判断:<c:if>。
- if...else:<choose>。类似于MySQL中的case一样。
二、分页查询。
(1)使用<c:forEach>循环拿对象,利用EL表达式显示属性。
- 使用"<%%>"、"<%=%>"嵌套代码看着很混乱。
- 则可以使用jstl标签完成操作!。
<% //从request域拿到数据 List<UserInfo> users = (List<UserInfo>) request.getAttribute("users"); for (UserInfo user : users) { %> <tr> <td><%=user.getId()%></td> <td><%=user.getName()%></td> <td><%=user.getGender()%></td> <td><%=user.getAge()%></td> <td><%=user.getAddress()%></td> <td><%=user.getEmail()%></td> <td><%=user.getQq()%></td> <td> <a class="btn btn-default btn-sm" href="/users/update?id=<%=user.getId()%>">修改</a> <a class="btn btn-default btn-sm" href="/users/delete?id=<%=user.getId()%>">删除</a></td> </tr> <% } %>
使用<c:forEach>标签。
从所有域中搜索键名"users"值。拿到应该List<UserInfo>集合。
<c:forEach items="${users}" var="user" varStatus="s">
items相当于Javaforeach循环中的"for(String str:str(数组/集合))"的数据集合。
var相当于某个体。
varStatus代表当前状态(如:位于第几行?)
<table border="1" class="table table-bordered table-hover"> <tr class="success"> <th>编号</th> <th>姓名</th> <th>性别</th> <th>年龄</th> <th>籍贯</th> <th>QQ</th> <th>邮箱</th> <th>操作</th> </tr> <c:forEach items="${users}" var="user" varStatus="s"> <tr> <td>${s.count}</td> <td>${user.name}</td> <td>${user.gender}</td> <td>${user.age}</td> <td>${user.address}</td> <td>${user.email}</td> <td>${user.qq}</td> <td> <a class="btn btn-default btn-sm" href="/users/update?id=${user.id}">修改</a> <a class="btn btn-default btn-sm" href="/users/delete?id=${user.id}">删除</a></td> </tr> </c:forEach> </table>
(2)通过Bootstrap获取分页栏组件快速渲染页面(jsp)。
- 渲染后。
(3)分页查询思路分析。
1、页面(前端)需要传什么参数?
- 页码。(当前位于第几页)
- 页容量。(每页显示的数据条数)
- 带条件的分页查询。
2、页面需要接收什么参数。
- 记录。(根据分页或条件查询的数据记录)
- 总记录。(查询的所有数据有多少条?)
- 总页数(最终分页)。(根据总记录与页容量计算!)
- 页码。
- 页容量。
- 将上面5个数据封装到Page类对象中,并存在域中!
- 将上面的5个数据封装成一个类Page。简单且实用。(面向对象)
3、Page类。
- totalPage(总页数)不能提供setter()方法。因为这个是根据总记录数和页容量进行计算。
- 如果有40条数据。每一页显示5条。则总页数 =8页。
- 如果有41条数据。每一页显示5条。则总页数 = 9页。
- 总页数 = 总记录数 % 页容量 == 0? 总记录数/页容量: 总记录数/页容量 +1。
public Long getTotalPage() { //总页数 = 总记录数 % 页容量 == 0? 总记录数/页容量: 总记录数/页容量 +1 return count%pageSize==0?count/pageSize:(count/pageSize+1); }
package com.fs.entity; import java.util.List; /** * @Title: Page * @Author HeYouLong * @Package com.fs.entity * @Date 2024/11/29 下午4:48 * @description: 分页实体类 */ public class Page<T> { private Long count ; //总记录数 private Long totalPage; //总页数 private Integer pageIndex; //当前页码 private Integer pageSize; //每页显示记录数(页容量) private List<T> records; // public Long getCount() { return count; } public void setCount(Long count) { this.count = count; } public Long getTotalPage() { return count % pageSize == 0 ? count / pageSize : (count / pageSize) + 1; } /*public void setTotalPage(Long totalPage) { this.totalPage = totalPage; }*/ public Integer getPageIndex() { return pageIndex; } public void setPageIndex(Integer pageIndex) { this.pageIndex = pageIndex; } public Integer getPageSize() { return pageSize; } public void setPageSize(Integer pageSize) { this.pageSize = pageSize; } public List<T> getRecords() { return records; } public void setRecords(List<T> records) { this.records = records; } }
4、sql语句的书写。
- sql语句需要写两条。调用两个方法。
- 记录(根据分页得到的查询结果)。
- 求当前页记录: select * from …. limit 开始序号,页容量。
- 总记录(count)。
- 求总记录数: select count(1) from…
- limit的开始序号与页容量。
- 开始序号 = (页码-1)*页容量。
- 如40条数据。每页5条。
- 页码 开始序号
- 1 0
- 2 5
- 3 10
三、正式代码书写。
(1)链接到对应Servlet。
(2)queryUsersByPageServlet类。
- 具体代码。具体解释在注释中。
package com.fs.web; import com.fs.entity.Page; import com.fs.entity.UserInfo; import com.fs.service.UserInfoService; import com.fs.service.impl.UserInfoServiceImpl; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; /** * @Title: queryUsersByPageServlet * @Author HeYouLong * @Package com.fs.web * @Date 2024/11/29 下午5:01 * @description: 分页查询用户信息 */ @WebServlet("/users/queryUsersByPage") public class queryUsersByPageServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.设置编码 resp.setContentType("text/html;charset=utf-8"); //获取请求参数 //页码 String pageIndexStr = req.getParameter("pageIndex"); int pageIndex = Integer.parseInt(pageIndexStr); //默认设置页容量=2 int pageSize = 2; //2.调用业务层 UserInfoService userInfoService = new UserInfoServiceImpl(); //调用分页查询方法 //注意返回的是一个封装了5个数据的Page对象 Page<UserInfo> page = userInfoService.queryByPage(pageIndex,pageSize); //将分页查询的所有用户信息保存到request域中 req.setAttribute("page",page); //请求转发 req.getRequestDispatcher("/users/list.jsp").forward(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } }
- 注意修改:将循环的EL表达式改成"page(对象)",并且是它的属性查询后的记录数(records)。
(3)service层接口。
/** * 分页查询 * @param pageIndex * @param pageSize * @return */ Page<UserInfo> queryByPage(int pageIndex, int pageSize);
(4)serviceImpl实现类。
- 注意这里需要写两个dao层方法。
- 1.查询总记录数。2.查询当前分页条件下的记录。(数据)
@Override public Page<UserInfo> queryByPage(int pageIndex, int pageSize) { UserInfoDao userInfoDao = new UserInfoDaoImpl(); //1.查询总记录数 long count = userInfoDao.count(); // 2.查询当前分页的记录(数据) List<UserInfo> records =userInfoDao.selectByPage(pageIndex,pageSize); //包装成page对象 Page<UserInfo> page = new Page<>(); page.setPageIndex(pageIndex); page.setPageSize(pageSize); page.setCount(count); page.setRecords(records); return page; } }
(5)dao层接口。(数据访问层接口)
/** * 查询总记录数 * @return */ long count(); /** * 分页查询 * @param pageIndex * @param pageSize * @return */ List<UserInfo> selectByPage(int pageIndex, int pageSize);
- 因为查询的结果是返回是一个基本数据类型的数据。
- 所以使用ScalarHandler类接收参数。
(6)dao层实现类。
@Override public long count() { Connection conn = null; try { conn = JdbcUtil.getConnection(); QueryRunner queryRunner = new QueryRunner(); String sql = "select count(1) from tb_userinfo"; //查询单个值,resultSet处理器 ScalarHandler return queryRunner.query(conn,sql,new ScalarHandler<Long>()); } catch (SQLException e) { throw new RuntimeException(e); }finally { JdbcUtil.close(conn); } } @Override public List<UserInfo> selectByPage(int pageIndex, int pageSize) { Connection conn = null; try { conn = JdbcUtil.getConnection(); QueryRunner queryRunner = new QueryRunner(); String sql = "select * from tb_userinfo limit ?,?"; return queryRunner.query(conn,sql,new BeanListHandler<>(UserInfo.class),(pageIndex-1)*pageSize,pageSize); } catch (SQLException e) { throw new RuntimeException(e); }finally { JdbcUtil.close(conn); } }
(7)初步测试其功能是否正常。
- 先登录。
- 进入首页。点击查询用户信息按钮。
- 功能正常。
- 现在对下面的分页栏进行修改。增加总记录数、总页数显示。
(8)完善设计要求。
(注意本代码中使用bootstrap组件快速开发)
1、当前所在页为:1。
- 不显示上一页按钮。点击下一页跳到下一页数据。
- 通过<c:if>标签进行判断。
2、当前所在页为:最后一页。
- 不显示下一页按钮。点击上一页跳到上一页数据。
3、位于当前页时。
- 从超链接变成不能点击的。以单纯文本显示。
- 所在按钮背景变"蓝"。
4、显示页数(如:1、2...)。
- 根据当前的分页总数计算。
- 根据<c:forEach>进行普通循环。
<%@ page import="com.fs.entity.UserInfo" %> <%@ page import="java.util.List" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%--引入JSTL核心标签库--%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <!-- 网页使用的语言 --> <html lang="zh-CN"> <head> <!-- 指定字符集 --> <meta charset="utf-8"> <!-- 使用Edge最新的浏览器的渲染方式 --> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <!-- viewport视口:网页可以根据设置的宽度自动进行适配,在浏览器的内部虚拟一个容器,容器的宽度与设备的宽度相同。 width: 默认宽度与设备的宽度相同 initial-scale: 初始的缩放比,为1:1 --> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --> <title>用户信息管理系统</title> <!-- 1. 导入CSS的全局样式 --> <link href="../css/bootstrap.min.css" rel="stylesheet"> <!-- 2. jQuery导入,建议使用1.9以上的版本 --> <script src="../js/jquery-2.1.0.min.js"></script> <!-- 3. 导入bootstrap的js文件 --> <script src="../js/bootstrap.min.js"></script> <style type="text/css"> td, th { text-align: center; } </style> </head> <body> <div class="container"> <h3 style="text-align: center">用户信息列表</h3> <div style="float: left;"> <form class="form-inline"> <div class="form-group"> <label for="exampleInputName2">姓名</label> <input type="text" class="form-control" id="exampleInputName2"> </div> <div class="form-group"> <label for="exampleInputName3">籍贯</label> <input type="text" class="form-control" id="exampleInputName3"> </div> <div class="form-group"> <label for="exampleInputEmail2">邮箱</label> <input type="email" class="form-control" id="exampleInputEmail2"> </div> <button type="submit" class="btn btn-default">查询</button> </form> </div> <div style="float: right;margin: 5px;"> <a class="btn btn-primary" href="add.html">添加新用户</a> <a class="btn btn-primary" href="add.html">删除选中用户</a> </div> <table border="1" class="table table-bordered table-hover"> <tr class="success"> <th><input type="checkbox"></th> <th>编号</th> <th>姓名</th> <th>性别</th> <th>年龄</th> <th>籍贯</th> <th>QQ</th> <th>邮箱</th> <th>操作</th> </tr> <c:forEach items="${page.records}" var="user" varStatus="s"> <tr> <td><input type="checkbox"></td> <td>${s.count}</td> <td>${user.name}</td> <td>${user.gender}</td> <td>${user.age}</td> <td>${user.address}</td> <td>${user.email}</td> <td>${user.qq}</td> <td> <a class="btn btn-default btn-sm" href="/users/update?id=${user.id}">修改</a> <a class="btn btn-default btn-sm" href="/users/delete?id=${user.id}">删除</a></td> </tr> </c:forEach> </table> <nav aria-label="Page navigation"> <ul class="pagination"> <li> <c:if test="${page.pageIndex>1}"> <a href="/users/queryUsersByPage?pageIndex=${page.pageIndex-1}" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </c:if> </li> <%--var相当于i begin 开始 end 结束 step 步长(每次加1)--%> <c:forEach var="i" begin="1" end="${page.totalPage}" step="1"> <c:choose> <c:when test="${page.pageIndex==i}"> <li class="active"><span>${i}</span></li> </c:when> <c:otherwise> <li><a href="/users/queryUsersByPage?pageIndex=${i}">${i}</a></li> </c:otherwise> </c:choose> </c:forEach> <li> <c:if test="${page.pageIndex <page.totalPage}"> <a href="/users/queryUsersByPage?pageIndex=${page.pageIndex+1}" aria-label="Next"> <span aria-hidden="true">»</span> </a> </c:if> </li> <span style="font-size: 25px;margin-left: 5px;"> 共条${page.count}记录,共${page.totalPage}页 </span> </ul> </nav> </div> </body> </html>
5、测试结果。
- 初步测试1。
- 位于第一页时,没有上一页按钮。
- 位于最后一页时,没有下一页按钮。
- 最终效果。