1.BookDao实现及测试
创建BookDao并定义实现书本查全部方法,最后完成Junit方法测试。
public class BookDao extends BaseDao<Book>{
/**
* 添加
* @param book
*/
public void addBook(Book book){
Connection con = null;
PreparedStatement ps = null;
try{
//获取连接对象
con=DBHelper.getConnection();
ps=con.prepareStatement("insert into t_book values(?,?,?,?)");
ps.setString(1,book.getBookid());
ps.setString(2,book.getBookname());
ps.setFloat(3,book.getPrice());
ps.setString(4,book.getBooktype());
//执行SQL语句并返回影响行数
int i=ps.executeUpdate();
if(i<0)
throw new Exception("执行失败,影响函数为0");
}catch (Exception e){
e.printStackTrace();
}finally {
DBHelper.close(con,ps,null);
}
}
/**
* 模糊查询
* @param book
* @return
*/
public List<Book> getByLike(Book book, PageBean pageBean) {
String sql = "select * from t_book where 1=1";
if (StringUtils.isNotBlank(book.getBookname()))
sql += " and bookname like '%" + book.getBookname() + "%'";
System.out.println(sql);
return super.executeQuery(sql, pageBean, new CallBack<Book>() {
@Override
public List<Book> foreachRs(ResultSet rs) throws SQLException {
return CommonUtils.toList(rs,Book.class);
}
});
}
}
2.BookServlet实现及页面效果展示
创建BookServlet并调用BookDao中查全部方法实现书本查询。
public class BookServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取前端页面传入的查询条件
String bookname = req.getParameter("bookname");
//创建Book对象
Book book=new Book();
book.setBookname(bookname);
//调用模糊查询方法
PageBean pageBean=new PageBean();
BookDao bookDao=new BookDao();
//获取前端传入的请求参数集
pageBean.setRequest(req);
List<Book> books = bookDao.getByLike(book,pageBean);
//将查询结果保存到request作用域中
req.setAttribute("books",books);
//将pageBean保存到request作用域中
req.setAttribute("pageBean",pageBean);
//转发
req.getRequestDispatcher("index.jsp").forward(req,resp);
}
}
1)打开web.xml,配置中文乱码过滤器EncodingFilter和书本查询Servlet控制器;
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--1、配置中文过滤器-->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>com.zking.pagintation.uitl.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--2、配置Servlet的servlet-->
<servlet>
<servlet-name>Servlet</servlet-name>
<servlet-class>com.zking.pagintation.servlet.BookServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet</servlet-name>
<url-pattern>/Servlet.do</url-pattern>
</servlet-mapping>
<!--3、配置欢迎页-->
<welcome-file-list>
<welcome-file>/index.jsp</welcome-file>
</welcome-file-list>
</web-app>
2)创建BookServlet.jsp页面实现书本查询效果展示。
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="z" uri="/zking" %>
<html>
<head>
<title>通用分页</title>
</head>
<body>
<h1>通用分页</h1>
<form method="post" action="Servlet.do">
<label>书本名称:</label><input type="text" name="bookname">
<input type="submit" value="查询">
</form>
<table width="100%" border="1" cellpadding="0" cellspacing="0">
<tr>
<th>书本编号</th>
<th>书本名称</th>
<th>书本价格</th>
<th>书本类型</th>
</tr>
<c:forEach var="b" items="${books}">
<tr>
<td>${b.bookid}</td>
<td>${b.bookname}</td>
<td>${b.price}</td>
<td>${b.booktype}</td>
</tr>
</c:forEach>
</table>
<z:pagination pageBean="${pageBean}"/>
</body>
</html>
3.通用分页实现
3.1.MySQL分页
-
limit语法
select * from table_name limit [offset,] rows
-
参数说明
参数 | 说明 |
---|---|
offset | 指定第一个返回记录行的偏移量(即从哪一行开始返回),注意:初始行的偏移量为0 |
rows | 返回具体行数 |
3.2.PageBean
创建PageBean分页标记类,用于定义分页相关要素。
/**
* 分页工具类
*/
public class PageBean {
//当前页码
private int page=1;
//每页条数
private int rows=10;
//总机录数
private int total=0;
//是否分页标记
private boolean pagination=true;
//增强属性
//返回上一条请求的url路径
private String url;
//获取上一次请求的所有请求参数集合
private Map<String,String[]> maps;
public void setRequest(HttpServletRequest req){
//1、获取前端传入的分页三要素(page,rows,pagination)
String page = req.getParameter("page");
String rows = req.getParameter("rows");
String pagination = req.getParameter("pagination");
this.setPage(page);
this.setRows(rows);
this.setPagination(pagination);
//2、获取上一次请求的URL路径
//req.getContextPath == 获取项目名
//req.getServletPath() == 获取servlet请求路径名
//req.getRequestURL == req.getContextPath+req.getServletPath()
this.url=req.getRequestURI();
//3、获取上一次请求的所有请求参数集合
this.maps = req.getParameterMap();
}
/**
* 返回limit分页查询的开始位置
* @return
*/
public int getStartIndex(){
return (this.page-1)*this.rows;
}
//重载set方法
public void setPage(String page) {
if(null!=page)
this.page = Integer.parseInt(page);
}
public void setRows(String rows) {
if(null!=rows)
this.rows = Integer.parseInt(rows);
}
public void setPagination(String pagination) {
if(null!=pagination)
this.pagination = Boolean.parseBoolean(pagination);
}
/**
* //分页方法
* //计算总分页
* @return 总分页数
*/
public int getMaxPager(){
int max = this.total/this.rows;
//除不尽有余数
if(this.total%this.rows!=0)
max++;
return max;
}
/**
* 上一页方法
* @return 上一页页数
*/
public int getPrevPager(){
int prev = this.page-1;
if(prev<=1)
prev=1;
return prev;
}
/**
* 下一页方法
* @return 下一页页数
*/
public int getNextPager(){
int next=this.page+1;
if(next>=getMaxPager())
next=getMaxPager();
return next;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Map<String, String[]> getMaps() {
return maps;
}
public void setMaps(Map<String, String[]> maps) {
this.maps = maps;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getRows() {
return rows;
}
public void setRows(int rows) {
this.rows = rows;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public boolean isPagination() {
return pagination;
}
public void setPagination(boolean pagination) {
this.pagination = pagination;
}
@Override
public String toString() {
return "PageBean{" +
"page=" + page +
", rows=" + rows +
", total=" + total +
", pagination=" + pagination +
", url='" + url + '\'' +
", maps=" + maps +
'}';
}
}
3.3.BaseDao
创建BaseDao通用分页类并定义相关分页方法。
3.3.1分页查询方法
public class BaseDao<T> {
/**
* 通用分页方法 (分页或不分页)
* @param sql 普通SQL语句
* @param pageBean 分页标记对象
* @return 返回分页结果集
*/
public List<T> executeQuery(String sql, PageBean pageBean,CallBack<T> callBack){
Connection con=null;
PreparedStatement ps=null;
ResultSet rs=null;
try{
con= DBHelper.getConnection();
if(null!=pageBean&&pageBean.isPagination()){
//分页
//1)根据满足的条件查询分页总记录数
String countSQL = this.getCountSQL(sql);
ps=con.prepareStatement(countSQL);
rs=ps.executeQuery();
if(rs.next()){
int total = rs.getInt(1);
//将查询得到的总记录数存入Page Bean对象中的total属性
pageBean.setTotal(total);
}
//2)根据满足的条件查询分页结果集
sql = this.getPagerSQL(sql, pageBean);
}
ps=con.prepareStatement(sql);
rs=ps.executeQuery();
return callBack.foreachRs(rs);
}catch (Exception e){
e.printStackTrace();
}finally {
DBHelper.close(con,ps,rs);
}
return null;
}
}
在executeQuery方法中根据PageBean对象及对象属性pagination识别是否分页。
-
分页:查询分页结果、集查询总记录数
-
将普通的SQL语句转换成分页查询的SQL语句
/**
* 将普通的SQL语句转换成分页查询的SQL语句
* @param sql 普通SQL语句
* @param pageBean 分页标记对象
* @return 分页查询的SQL语句
*/
private String getPagerSQL(String sql,PageBean pageBean){
return sql+" limit "+pageBean.getStartIndex()+","+pageBean.getRows();
}
- 将普通sql语句转换成查总记录数的sql
/**
* 将普通sql语句转换成查总记录数的sql
* @param sql
* @return 查询总记录数的SQL语句
*/
private String getCountSQL(String sql){
return "select count(*) from ("+sql+") temp";
}
-
不分页:只查询数据结果集(不查询分页记录和总记录数)
3.3.2.匿名内部接口
在BaseDao类中定义匿名内部接口,该接口中的forEach方法只用于循环遍历ResultSet查询结果集并返回List<T>
/**
* 用于遍历结果集数据的回调接口
* @author Administrator
* @param <T>
*/
public static interface CallBack<T>{
public List<T> foreachRs(ResultSet rs) throws SQLException;
}
修改executeQuery方法,将匿名内部接口CallBack当做入参传入方法中。
public List<T> executeQuery(String sql, PageBean pageBean,CallBack<T> callBack){
Connection con=null;
PreparedStatement ps=null;
ResultSet rs=null;
try{
con= DBHelper.getConnection();
if(null!=pageBean&&pageBean.isPagination()){
//分页
//1)根据满足的条件查询分页总记录数
String countSQL = this.getCountSQL(sql);
ps=con.prepareStatement(countSQL);
rs=ps.executeQuery();
if(rs.next()){
int total = rs.getInt(1);
//将查询得到的总记录数存入Page Bean对象中的total属性
pageBean.setTotal(total);
}
//2)根据满足的条件查询分页结果集
sql = this.getPagerSQL(sql, pageBean);
}
ps=con.prepareStatement(sql);
rs=ps.executeQuery();
return callBack.foreachRs(rs);
}catch (Exception e){
e.printStackTrace();
}finally {
DBHelper.close(con,ps,rs);
}
return null;
}
3.3.3.Junit单元测试
Junit是一个Java测试框架,使编写可靠和高效的测试变得容易。它可以用于大多数语言制作的应用程序,但特别适合于测试Java应用程序。Junit也可以用来创建自动测试。
Junit框架是最流行的Java测试框架之一。它提供了一些功能,使编写测试变得容易,包括支持多个测试用例、断言和报告。Junit也是多功能的,允许用各种语言编写测试。
setUp():在方法之前执行
tearDown:在方法之后执行
public class BookDaoTest {
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void testQueryBookPager() {
fail("Not yet implemented");
}
}
Junit中的setUp和tearDown方法是根据方法数量来决定的
4.增强PageBean
package com.zking.pagintation.uitl;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* 分页工具类
*/
public class PageBean {
//当前页码
private int page=1;
//每页条数
private int rows=10;
//总机录数
private int total=0;
//是否分页标记
private boolean pagination=true;
//增强属性
//返回上一条请求的url路径
private String url;
//获取上一次请求的所有请求参数集合
private Map<String,String[]> maps;
public void setRequest(HttpServletRequest req){
//1、获取前端传入的分页三要素(page,rows,pagination)
String page = req.getParameter("page");
String rows = req.getParameter("rows");
String pagination = req.getParameter("pagination");
this.setPage(page);
this.setRows(rows);
this.setPagination(pagination);
//2、获取上一次请求的URL路径
//req.getContextPath == 获取项目名
//req.getServletPath() == 获取servlet请求路径名
//req.getRequestURL == req.getContextPath+req.getServletPath()
this.url=req.getRequestURI();
//3、获取上一次请求的所有请求参数集合
this.maps = req.getParameterMap();
}
/**
* 返回limit分页查询的开始位置
* @return
*/
public int getStartIndex(){
return (this.page-1)*this.rows;
}
//重载set方法
public void setPage(String page) {
if(null!=page)
this.page = Integer.parseInt(page);
}
public void setRows(String rows) {
if(null!=rows)
this.rows = Integer.parseInt(rows);
}
public void setPagination(String pagination) {
if(null!=pagination)
this.pagination = Boolean.parseBoolean(pagination);
}
/**
* //分页方法
* //计算总分页
* @return 总分页数
*/
public int getMaxPager(){
int max = this.total/this.rows;
//除不尽有余数
if(this.total%this.rows!=0)
max++;
return max;
}
/**
* 上一页方法
* @return 上一页页数
*/
public int getPrevPager(){
int prev = this.page-1;
if(prev<=1)
prev=1;
return prev;
}
/**
* 下一页方法
* @return 下一页页数
*/
public int getNextPager(){
int next=this.page+1;
if(next>=getMaxPager())
next=getMaxPager();
return next;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Map<String, String[]> getMaps() {
return maps;
}
public void setMaps(Map<String, String[]> maps) {
this.maps = maps;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getRows() {
return rows;
}
public void setRows(int rows) {
this.rows = rows;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public boolean isPagination() {
return pagination;
}
public void setPagination(boolean pagination) {
this.pagination = pagination;
}
@Override
public String toString() {
return "PageBean{" +
"page=" + page +
", rows=" + rows +
", total=" + total +
", pagination=" + pagination +
", url='" + url + '\'' +
", maps=" + maps +
'}';
}
}
5.创建自定义分页标签
5.1.创建自定义分页标签助手类
package com.zking.pagintation.tag;
import com.zking.pagintation.uitl.PageBean;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
import java.util.Map;
import java.util.Set;
public class PaginationTag extends BodyTagSupport {
private PageBean pageBean;
public PageBean getPageBean() {
return pageBean;
}
public void setPageBean(PageBean pageBean) {
this.pageBean = pageBean;
}
@Override
public int doStartTag() throws JspException {
try{
JspWriter out = pageContext.getOut();
out.print(toHtml());
}catch (Exception e){
e.printStackTrace();
}
return SKIP_BODY;
}
private String toHtml(){
//判断PageBean是否为空
if(null!=pageBean&&pageBean.isPagination()){
//定义StringBuffer可变字符串
//面试题:String/StringBuffer/StringBuilder/的区别
StringBuffer sb=new StringBuffer();
//拼接div跟标签
sb.append("<div style=\"float: right;\">");
//拼接form标签对象
sb.append("<form id=\"pageForm\" method=\"post\" action="+pageBean.getUrl()+">");
//拼接page隐藏域
sb.append(" <input type=\"hidden\" name=\"page\"/>");
//获取请求参数集合
Map<String,String[]> maps=pageBean.getMaps();
//获取请求参数集合的键值对
Set<Map.Entry<String, String[]>> entries = maps.entrySet();
//循环遍历请求参数键值对
for (Map.Entry<String, String[]> entry : entries) {
//判断请求参数是否是page,如果是 则continue
if(entry.getKey().equalsIgnoreCase("page"))
continue;
//获取请求参数的value值(类型为String[])
String[] values = entry.getValue();
//循环遍历value值
for(String value : values){
sb.append("<input type='hidden' name='"+entry.getKey()+"' value='"+value+"'>");
}
}
sb.append("</form>");
//拼接分页信息
sb.append("第"+pageBean.getPage()+"页/总"+pageBean.getMaxPager()+"页数");
//拼接首页、上一页、下一页、末页
if(pageBean.getPage()==1)
sb.append("首页 上一页");
else {
sb.append("<a onclick=\"gotoPage(1)\" href=\"javascript:void(0);\">首页</a>");
sb.append("<a onclick=\"gotoPage("+pageBean.getPrevPager()+")\" href=\"javascript:void(0);\">上一页</a>");
}
if(pageBean.getPage()==pageBean.getMaxPager())
sb.append("下一页 末页");
else {
sb.append("<a onclick=\"gotoPage("+pageBean.getNextPager()+")\" href=\"javascript:void(0);\">下一页</a>");
sb.append("<a onclick=\"gotoPage("+pageBean.getMaxPager()+")\" href=\"javascript:void(0);\">末页</a>");
}
//拼接javascpit
sb.append("<script>\n" +
" function gotoPage(page){\n" +
" document.getElementById('pageForm').page.value=page;\n" +
" document.getElementById('pageForm').submit();\n" +
" }\n" +
"</script>");
sb.append("</div>");
return sb.toString();
}
return "";
}
@Override
public int doEndTag() throws JspException {
return EVAL_PAGE;
}
}
5.2.导入标签描述文件
详见课件"z.tld"文件