版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33621967/article/details/53246926
效果图展示:
基本框架(预览):
代码实现:
前端页面
主页(index.jsp)
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
<!-- 经实测,c:redirect标记内不能用c:url -->
<c:redirect url="/PageServlet"></c:redirect>
</body>
</html>
servlet层
PageServlet.java
package cn.hncu.servlet;
import java.io.IOException;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.hncu.service.IPageService;
import cn.hncu.service.PageServiceImpl;
public class PageServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
//注入service层
IPageService service = new PageServiceImpl();
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//作用:拿到前端页面的用户选择的页面面数
String pageNo = request.getParameter("pageNo");
if(pageNo==null || "".equals(pageNo.trim())){//用户第一次进入分页页面还没有进行选择页面的情况
pageNo = "1";
}
try {
//将页面进行转换成整数的形式
int iPageNo = Integer.valueOf(pageNo);//从前台页面拿到的数据!
Map<String, Object> result = service.query(iPageNo);
result.put("currentPage", iPageNo);//将当前页面同样封装到集合中去!
/*
* 理一下:map集合中一共封装了三个数据:1)总页数--dao层封装 2)所有数据行信息--dao层封装
* 3)当前页数--servlet层进行封装
*/
//数据封装完之后必须记得添加到容器中!
request.setAttribute("result", result);
//转发到前台页面进行相应的显示!
request.getRequestDispatcher("/jsps/show.jsp").forward(request, response);
} catch (NumberFormatException e) {
response.getWriter().println("页面格式转换错误!");
} catch (Exception e) {
response.getWriter().println("数据库查询错误!");
}
}
}
service层
接口(PageService.java)
package cn.hncu.service;
import java.util.Map;
public interface IPageService {
public abstract Map<String, Object> query(Integer pageNo) throws Exception;
}
实现类(PageServiceImpl.java)
package cn.hncu.service;
import java.util.Map;
import cn.hncu.dao.PageDAO;
import cn.hncu.dao.PageDAOJdbc;
public class PageServiceImpl implements IPageService {
//以现在的技术还是只能够依赖注入,等学到后面就就可以更高级的方法弄了-----注入dao层
PageDAO dao = new PageDAOJdbc();
@Override
public Map<String, Object> query(Integer pageNo) throws Exception {
return dao.query(pageNo);
}
}
DAO层
接口(PageDAO.java)
package cn.hncu.dao;
import java.util.Map;
public interface PageDAO {
public abstract Map<String, Object> query(Integer pageNo) throws Exception;
}
实现类(PageDAOImpl.java)
package cn.hncu.dao;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import cn.hncu.pubs.C3p0Utils;
public class PageDAOJdbc implements PageDAO {
@Override
public Map<String, Object> query(Integer pageNo) throws Exception {
//dao层进行封装的数据包含:1)一共包含多少页面 2)所有行数据
Map<String, Object> result = new HashMap<String, Object>();
//首选计算出总页数
int pageSize = 10;
//从数据库中拿到总行数!
String sql = "select count(1) from person";
QueryRunner run = new QueryRunner(C3p0Utils.getDataSource());
Object obj = run.query(sql, new ScalarHandler());
//转换成整数
int rows = Integer.valueOf(String.valueOf(obj));//拿到总行数
//根据总行数计算出纵页数
int pageCount = rows/pageSize +(rows%pageSize==0?0:1);//页数
//添加到集合中去
result.put("pageCount", pageCount);
int startN = (pageNo-1)*pageSize;
sql = "select * from person limit "+startN+","+pageSize;
//封装所有行数据
List<Map<String, Object>> datas = run.query(sql, new MapListHandler());
result.put("datas", datas);
return result;
}
}
DAO访问数据库中的数据
上面需要用到的工具类(拿到连接对象DbUtils)
C3p0Utils.java
package cn.hncu.pubs;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3p0Utils {
//本地线程管理对象,用于实现: 同一个线程获取的连接是同一个
private static ThreadLocal<Connection> t = new ThreadLocal<Connection>();
private static DataSource pool =null;
static{
try {
//配置文件和当前类放在一起
pool = new ComboPooledDataSource();//使用默认配置项
} catch (Exception e) {
e.printStackTrace();
}
}
public static DataSource getDataSource(){
return pool;
}
public static Connection getConn() {
//先从t中拿,如果有就拿出去,如果没有再到池中拿且把该对象放到t中
Connection con = t.get();
if(con==null){
try {
con = pool.getConnection();
t.set(con); //放到t中
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
System.out.println("获取一个连接:"+con.hashCode());
return con;
}
}
相应的配置文件(c3p0-config.xml)
<c3p0-config>
<!-- 默认配置,如果没有指定则使用这个配置 -->
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">
<![CDATA[jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=UTF-8]]>
</property>
<property name="user">root</property>
<property name="password">1234</property>
<!-- 初始化池大小 -->
<property name="initialPoolSize">2</property>
<!-- 最大空闲时间 -->
<property name="maxIdleTime">30</property>
<!-- 最多有多少个连接 -->
<property name="maxPoolSize">10</property>
<!-- 最少几个连接 -->
<property name="minPoolSize">2</property>
<!-- 每次最多可以执行多少个批处理语句 -->
<property name="maxStatements">50</property>
</default-config>
<!-- 命名的配置 -->
<named-config name="demo">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">
<![CDATA[jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=UTF-8]]>
</property>
<property name="user">root</property>
<property name="password">1234</property>
<property name="acquireIncrement">5</property><!-- 如果池中数据连接不够时一次增长多少个 -->
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">15</property>
<property name="maxStatements">0</property>
<property name="maxStatementsPerConnection">5</property> <!-- he's important, but there's only one of him -->
</named-config>
</c3p0-config>
结果页面显示
show.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<style type="text/css">
table{
border: 1px solid red;
border-collapse: collapse;
width: 150px;
}
td{
border: 1px solid red;
}
</style>
<title>分页结果页面</title>
<script type="text/javascript">
function sub(obj){
window.location.href="<c:url value='/PageServlet?pageNo="+obj.value+"' />";
}
</script>
</head>
<body>
<!-- 前端页面实现用到的技术:JSTL(c标签--很强!)+EL表达式 -->
<!-- 下面是把所有的数据全部输出来了 -->
<table>
<tr> <th>学号</th> <th>姓名</th> </tr>
<c:forEach items="${result.datas}" var="map">
<tr> <td>${map.id}</td> <td>${map.name }</td> </tr>
</c:forEach>
</table>
<hr/>
<!-- 在这个上面添加上一页的功能(添加这个功能之前还需要判断当前页面是否为第一页,如果为第一页则不显示上一页) -->
<c:if test="${result.currentPage!=1 }">
<a href="<c:url value='/PageServlet?pageNo=${result.currentPage-1}' />">
上一页
</a>
</c:if>
<c:forEach begin="1" end="${result.pageCount }" var="idx">
<!-- 给页面添加超链接操作! -->
<c:if test="${result.currentPage!=idx }">
<!-- 超链接方式进行传参 -->
<a href="<c:url value='/PageServlet?pageNo=${idx }'/>"><!-- 这种写法穿透能力很强啊! -->
${idx }
</a>
</c:if>
<c:if test="${result.currentPage==idx }">
${idx }
</c:if>
</c:forEach>
<!-- 在这个下面添加下一页的功能(添加这个功能之前还需要判断当前页面是否为最后一页,如果为最后一页则不显示下一页) -->
<c:if test="${result.currentPage!=result.pageCount }">
<a href="<c:url value='/PageServlet?pageNo=${result.currentPage+1}' />">
下一页
</a>
</c:if>
<!-- 接下来演示一个淘汰的技术--也不算淘汰吧,就是现在的技术基本不用这个功能了 -->
<br/><br/>
<select onchange="sub(this)">
<c:forEach begin="1" end="${result.pageCount }" var="idx">
<option <c:if test="${idx==result.currentPage }">selected="selected"</c:if> value="${idx }">第${idx }页</option>
</c:forEach>
</select>
</body>
</html>