Detailed explanation of JSP custom general pagination

Table of contents

Foreword:

1. Packaging tools

1. Analyze data

2. Database configuration file

3. Database helper class

4. Bytecode filter

5. Empty class for strings

6. Pagination tool class

2. General paging instance (backend)

         1. Define data objects

2. Native dao layer query method

3. BaseDao pagination method

4. BookDao pagination method

5. Backend data test

6. Use the JUnit test framework to test data

1. Introduction to JUnit

2. Configure the JUnit step

3. Test case

3.1 Directly run the interface results

3.2 Click the method name to run

3. JSP general paging instance (front end)

1. The core idea of ​​business division

2. Optimize the PageBean tool class

3. Custom page tag description file

4. Page helper class

5. BookServlet class

6. JSP page writing

7. Front-end interface display

Summarize:


Foreword:

        In the actual java web project  development process, we often use the paging function because there is a lot of data to be displayed, especially for the paging of different data tables, we need to write a lot of repetitive codes, so we design a general paging function, which can paginate different data tables, thereby simplifying the code and improving development efficiency.


1. Packaging tools

1. Analyze data

        1. First of all, where to get the data according to the needs, here is MySql as an example

        2. Define the required sql statement

        3. It is necessary to know whether there are multiple objects encapsulated by the content to be displayed

        4. Simplify the code according to native pagination

        4. Find common features and duplicate codes for encapsulation

2. Database configuration file

        The connection data of four different databases are encapsulated here, and the data can be modified according to your own computer configuration (the file is called)

#oracle9i
#driver=oracle.jdbc.driver.OracleDriver
#url=jdbc:oracle:thin:@localhost:1521:orcl
#user=scott
#pwd=123


#sql2005
#driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
#url=jdbc:sqlserver://localhost:1433;DatabaseName=test1
#user=sa
#pwd=123


#sql2000
#driver=com.microsoft.jdbc.sqlserver.SQLServerDriver
#url=jdbc:microsoft:sqlserver://localhost:1433;databaseName=unit6DB
#user=sa
#pwd=888888


#mysql
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis_ssm?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
user=root
pwd=123456



3. Database helper class

        Here is a set of methods to get or close the database object, it will read the database configuration file, as above (config.properties)

package com.ycxw.utils;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * 数据库帮助类
 * 作用:
 * 提供了一组获得或关闭数据库对象的方法
 * @author 云村小威
 */
public class DBAccess {
	private static String driver;
	private static String url;
	private static String user;
	private static String password;

	static {// 静态块执行一次,加载 驱动一次
		try {
			InputStream is = DBAccess.class.getResourceAsStream("config.properties");

			Properties properties = new Properties();
			properties.load(is);

			driver = properties.getProperty("driver");
			url = properties.getProperty("url");
			user = properties.getProperty("user");
			password = properties.getProperty("pwd");

			Class.forName(driver);
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	/**
	 * 获得数据连接对象
	 * 
	 * @return
	 */
	public static Connection getConnection() {
		try {
			Connection conn = DriverManager.getConnection(url, user, password);
			return conn;
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	public static void close(ResultSet rs) {
		if (null != rs) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
		}
	}

	public static void close(Statement stmt) {
		if (null != stmt) {
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
		}
	}

	public static void close(Connection conn) {
		if (null != conn) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
		}
	}

	public static void close(Connection conn, Statement stmt, ResultSet rs) {
		close(rs);
		close(stmt);
		close(conn);
	}

	public static boolean isOracle() {
		return "oracle.jdbc.driver.OracleDriver".equals(driver);
	}

	public static boolean isSQLServer() {
		return "com.microsoft.sqlserver.jdbc.SQLServerDriver".equals(driver);
	}

	public static boolean isMysql() {
		return "com.mysql.cj.jdbc.Driver".equals(driver);
	}

	public static void main(String[] args) {
		Connection conn = DBAccess.getConnection();
		System.out.println(conn);
		DBAccess.close(conn);
		System.out.println("isOracle:" + isOracle());
		System.out.println("isSQLServer:" + isSQLServer());
		System.out.println("isMysql:" + isMysql());
		System.out.println("数据库连接(关闭)成功");
	}
}

4. Bytecode filter

package com.ycxw.utils;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 字节码过滤器
 * 作用:
 * 中文乱码处理
 * @author 云村小威
 */
public class EncodingFiter implements Filter {

	private String encoding = "UTF-8";// 默认字符集

	public EncodingFiter() {
		super();
	}

	public void destroy() {
	}

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse res = (HttpServletResponse) response;

		// 中文处理必须放到 chain.doFilter(request, response)方法前面
		res.setContentType("text/html;charset=" + this.encoding);
		if (req.getMethod().equalsIgnoreCase("post")) {
			req.setCharacterEncoding(this.encoding);
		} else {
			Map map = req.getParameterMap();// 保存所有参数名=参数值(数组)的Map集合
			Set set = map.keySet();// 取出所有参数名
			Iterator it = set.iterator();
			while (it.hasNext()) {
				String name = (String) it.next();
				String[] values = (String[]) map.get(name);// 取出参数值[注:参数值为一个数组]
				for (int i = 0; i < values.length; i++) {
					values[i] = new String(values[i].getBytes("ISO-8859-1"),
							this.encoding);
				}
			}
		}

		chain.doFilter(request, response);
	}

	public void init(FilterConfig filterConfig) throws ServletException {
		String s = filterConfig.getInitParameter("encoding");// 读取web.xml文件中配置的字符集
		if (null != s && !s.trim().equals("")) {
			this.encoding = s.trim();
		}
	}

}

5. Empty class for strings

package com.ycxw.utils;

/**
 * 字符串判断工具类
 * @author 云村小威
 *
 */
public class StringUtils {
	// 私有的构造方法,保护此类不能在外部实例化
	private StringUtils() {
	}

	/**
	 * 如果字符串等于null或去空格后等于"",则返回true,否则返回false
	 * 
	 * @param s
	 * @return
	 */
	public static boolean isBlank(String s) {
		boolean b = false;
		if (null == s || s.trim().equals("")) {
			b = true;
		}
		return b;
	}

	/**
	 * 如果字符串不等于null或去空格后不等于"",则返回true,否则返回false
	 * 
	 * @param s
	 * @return
	 */
	public static boolean isNotBlank(String s) {
		return !isBlank(s);
	}

}

6. Pagination tool class

       Four property page numbers, the number of displayed data, the total number of records, and whether to paginate are defined here, which can be added or changed according to requirements

package com.ycxw.utils;

/**
 * 分页工具类
 * 
 * @author 云村小威
 */
public class PageBean {

	private int page = 1;// 页码

	private int rows = 10;// 页大小

	private int total = 0;// 总记录数

	private boolean pagination = true;// 是否分页

	public PageBean() {
		super();
	}

	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 void setTotal(String total) {
		this.total = Integer.parseInt(total);
	}

	public boolean isPagination() {
		return pagination;
	}

	public void setPagination(boolean pagination) {
		this.pagination = pagination;
	}

	/**
	 * 获得起始记录的下标
	 * 
	 * @return
	 */
	public int getStartIndex() {
		return (this.page - 1) * this.rows;
	}

	@Override
	public String toString() {
		return "PageBean [page=" + page + ", rows=" + rows + ", total=" + total + ", pagination=" + pagination + "]";
	}

}

2. General paging instance (backend)

1. Define data objects

        Only one entity is written here for testing, taking book as an example

package com.ycxw.entity;

/**
 * 实体类
 * @author 云村小威
 *
 */
public class Book {
	private int bid;
	private String bname;
	private float price;

	@Override
	public String toString() {
		return "Book [bid=" + bid + ", bname=" + bname + ", price=" + price + "]";
	}

	public int getBid() {
		return bid;
	}

	public void setBid(int bid) {
		this.bid = bid;
	}

	public String getBname() {
		return bname;
	}

	public void setBname(String bname) {
		this.bname = bname;
	}

	public float getPrice() {
		return price;
	}

	public void setPrice(float price) {
		this.price = price;
	}
	
	public Book() {
		// TODO Auto-generated constructor stub
	}

	public Book(int bid, String bname, float price) {
		super();
		this.bid = bid;
		this.bname = bname;
		this.price = price;
	}

}

2. Native dao layer query method

   This method queries all data

package com.ycxw.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.ycxw.entity.Book;
import com.ycxw.utils.BaseDao;
import com.ycxw.utils.DBAccess;
import com.ycxw.utils.PageBean;
import com.ycxw.utils.StringUtils;

/**
 * 数据访问层
 * 
 * @author 云村小威
 *
 */
public class BookDao{
	// 原始方法
	public List<Book> list(Book book, PageBean pageBean) throws SQLException {
		List<Book> list = new ArrayList<Book>();

		// 调用DBAccess获取数据库连接方法
		Connection con = DBAccess.getConnection();
		// 编写sql语句
		String sql = "select * from t_mvc_book where 1=1";
		String bname = book.getBname();
		// 调用判断bname是否为空
		if (StringUtils.isNotBlank(bname)) {
			sql += "and bname like '%" + bname + "%'";
		}
		// 执行sql语句
		PreparedStatement pre = con.prepareStatement(sql);
		// 将结果保存到结果集对象中
		ResultSet rs = pre.executeQuery();
		// 遍历添加到集合
		while (rs.next()) {
			list.add(new Book(rs.getInt("bid"), rs.getString("bname"), rs.getFloat("price")));
		}
		// 返回指定结果
		return list;
	}
}

3. BaseDao pagination method

      Optimize according to query method:

  • Encapsulate repetitive code, such as data connection, SQL execution, etc.
  • Use generics and reflection to dynamically manipulate data, because there may be data in multiple data tables in the future, each of which must write a method
  • Call the pageBean tool class for paging operations
package com.ycxw.utils;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

/**
 * 
 * @author 云村小威
 *
 */
public class BaseDao<T> {

	/**
	 * 分页查询方法
	 * 
	 * @param sql
	 * @param cla
	 * @param pageBean
	 * @return
	 * @throws Exception
	 */
	public List<T> executeQuery(String sql, Class<?> cla, PageBean pageBean) throws Exception {
		List<T> list = new ArrayList<T>();
		// 连接对象
		Connection con = null;
		// 执行对象
		PreparedStatement pre = null;
		// 结果集对象
		ResultSet rs = null;

		/**
		 * 判断pageBean是否为空,和是否分页 
		 * pageBean.isPagination() 返回false 不分页
		 */
		if (pageBean != null && pageBean.isPagination()) {
			// 获取总记录数
			String countSQL = getCountSQL(sql);
			con = DBAccess.getConnection();
			pre = con.prepareStatement(countSQL);
			rs = pre.executeQuery();
			if (rs.next()) {
				pageBean.setTotal(rs.getObject(1).toString());
			}
			// 获取显示记录数
			String pageSQL = getPageSQL(sql, pageBean);
			con = DBAccess.getConnection();
			pre = con.prepareStatement(pageSQL);
			rs = pre.executeQuery();
		} else {
			con = DBAccess.getConnection();
			pre = con.prepareStatement(sql);
			rs = pre.executeQuery();
		}

		// 遍历添加到集合
		while (rs.next()) {
			// 通过类对象newInstance方法创建一个对象
			@SuppressWarnings("unchecked")
			T t = (T) cla.newInstance();
			// 通过反射拿到对象所用属性
			Field[] fields = cla.getDeclaredFields();
			for (Field field : fields) {
				// 打开修饰符访问全向
				field.setAccessible(true);
				// 给属性赋值
				// 1. getObject()根据属性名获取值 2.field.getName()获取属性名
				field.set(t, rs.getObject(field.getName()));
			}
			//将对象添加到集合
			list.add(t);
		}
		// 返回指定结果
		return list;
	}
	
	/**
	 * 获取显示记录数
	 * @param sql 原生sql
	 * @param pageBean
	 * @return
	 */
	private String getPageSQL(String sql, PageBean pageBean) {
		return sql + " limit " + pageBean.getStartIndex() + "," + pageBean.getRows();
	}

	/**
	 * 获取总记录数
	 * @param sql
	 * @return
	 */
	private String getCountSQL(String sql) {
		return "select count(1) from (" + sql + ") t";
	}
}

4. BookDao pagination method

package com.ycxw.dao;

import java.util.List;

import com.ycxw.entity.Book;
import com.ycxw.utils.BaseDao;
import com.ycxw.utils.PageBean;
import com.ycxw.utils.StringUtils;

/**
 * 数据访问层
 * 
 * @author 云村小威
 *
 */
public class BookDao extends BaseDao<Book> {
	
	/**
	 * 模糊查询加分页方法
	 * @param book
	 * @param pageBean
	 * @return
	 * @throws Exception
	 */
	public List<Book> list(Book book, PageBean pageBean) throws Exception {
		// 编写sql语句
		String sql = "select * from t_mvc_book where 1=1";
		String bname = book.getBname();
		// 调用判断bname是否为空
		if (StringUtils.isNotBlank(bname)) {
			sql += " and bname like '%" + bname + "%'";
		}
		// 继承BaseDao类调用分页查询方法
		return super.executeQuery(sql, book.getClass(), pageBean);
	}


}

5. Backend data test

package com.ycxw.serlvet;

import java.util.List;

import com.ycxw.dao.BookDao;
import com.ycxw.entity.Book;
import com.ycxw.utils.PageBean;

/**
 * 分页数据测试类
 * @author 云村小威
 *
 */
public class Text {
	public static void main(String[] args) throws Exception {
		//实例化BookDao类
		BookDao dao = new BookDao();
		List<Book> list = dao.list(new Book(), new PageBean());
		for (Book book : list) {
			System.out.println(book);
		}
	}
}

operation result:

6. Use the JUnit test framework to test data

1. Introduction to JUnit

        JUnit is a unit testing framework for the Java programming language. It provides a set of annotations and assertion methods to write and run unit tests. Developers can use annotations to mark test methods and assert methods to verify that expected results match actual results.

The benefits of unit testing with JUnit include:

  • Automated testing: JUnit provides an automated testing process, reducing the workload of manual testing.
  • Fast Feedback: Running unit tests can quickly find problems in the code, helping developers fix bugs early.
  • Repeatability: Ensure that code behaves consistently in different environments by writing repeatable test cases.
  • Refactoring support: Running unit tests can verify that the refactored code still works as expected, avoiding introducing new problems.

        In conclusion, JUnit is a commonly used unit testing framework that helps developers write, run, and manage unit tests for Java code to ensure code quality and functional correctness.

2. Configure the JUnit step

1. Right-click the project and go to Build Path -- Click Configure Build Path...

 2. Click Add Library on the right list and double-click JUnit

3. Select JUnit4 and finish directly to configure it!

3. Test case

   Marked by @Test

/**
	 * 配置Junit可测试多个方法
	 * 
	 * @throws Exception
	 */
	@Test
	public void text() throws Exception {
		System.out.println("Text1...");
		BookDao bookDao = new BookDao();
		Book book = new Book();
		PageBean pageBean = new PageBean();
		List<Book> list = bookDao.list(book, pageBean);
		for (Book book1 : list) {
			System.out.println(book1.toString());
		}
	}

	@Test
	public void text2() throws Exception {
		System.out.println("Text2...");
		BookDao bookDao = new BookDao();
		Book book = new Book();
		book.setBname("圣墟");
		PageBean pageBean = new PageBean();
		// 设置页码
		pageBean.setPage(2);
		pageBean.setPagination(true);
		List<Book> list = bookDao.list(book, pageBean);
		for (Book book1 : list) {
			System.out.println(book1.toString());
		}
	}

3.1 Directly run the interface results

will output all while running

3.2 Click the method name to run

 operation result:

3. JSP general paging instance (front end)

1. The core idea of ​​business division

 1. The first query: execute pageBean default parameters

     bname=null  page=1  rows=10 pagination=true

2. The second query: enter 'Shengxu' query in the input box, and the background will get the following parameters

     bname=圣墟  page=1  rows=10 pagination=true

3. The third query: click next page

     bname=圣墟  page=2  rows=10 pagination=true

4. The fourth query:

     Conclusion: Compared with the last query, except for the page number, other parameters do not change, so two parameters need to be added compared to the backend.

2. Optimize the PageBean tool class

package com.ycxw.utils;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

/**
 * 分页工具类
 * 
 * @author 云村小威
 */
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[]> parameterMap = new HashMap<String, String[]>();

	// 对pagebean进行初始化
	public void setRequest(HttpServletRequest req) {
		// 初始化jsp页面传递过来的当前页
		this.setPage(req.getParameter("page"));
		// 初始化jsp页面传递过来的页大小
		this.setRows(req.getParameter("rows"));
		// 初始化jsp页面传递过来是否分页
		this.setPagination(req.getParameter("pagination"));
		// 保留上一次的查询请求
		this.setUrl(req.getRequestURL().toString());
		// 保留上一次的查询条件
		this.setParameterMap(req.getParameterMap());
	}
	
	private void setPagination(String pagination) {
		// 只有填写了false字符串,才代表不分页
		this.setPagination(!"false".equals(pagination));
	}

	private void setRows(String rows) {
		//判空处理
		if (StringUtils.isNotBlank(rows))
			this.setRows(Integer.valueOf(rows));
	}

	private void setPage(String page) {
		//判空处理
		if (StringUtils.isNotBlank(page))
			this.setPage(Integer.valueOf(page));
	}
	
	/**
	 * 获得起始记录的下标
	 * 
	 * @return
	 */
	public int getStartIndex() {
		return (this.page - 1) * this.rows;
	}

	// 上一页
	public int getPrevPage() {
		return this.page > 1 ? this.page - 1 : this.page;
	}

	// 下一页
	public int getNextPage() {
		return this.page < this.getMaxPage() ? this.page + 1 : this.page;
	}

	// 最大页
	public int getMaxPage() {
		return this.total % this.rows == 0 ? this.total / this.rows : (this.total / this.rows) + 1;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public Map<String, String[]> getParameterMap() {
		return parameterMap;
	}

	public void setParameterMap(Map<String, String[]> parameterMap) {
		this.parameterMap = parameterMap;
	}

	public PageBean() {
		super();
	}

	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 void setTotal(String total) {
		this.total = Integer.parseInt(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 + "]";
	}

}

3. Custom page tag description file

<!-- page.tld -->
<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
	version="2.0">
	<description>My custom tag library</description>
	<display-name>My Tag Library</display-name>
	<tlib-version>1.0</tlib-version><!-- 代表标签库的版本号 -->
	<short-name>w</short-name><!-- 你的标签库简称 -->
	<uri>com.ycxw</uri><!-- taglib引入标签名字 -->
	<tag>
		<name>page</name>
		<tag-class>com.ycxw.tag.PageTag</tag-class>
		<body-content>JSP</body-content>
		<attribute>
			<name>pageBean</name>
			<required>true</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
	</tag>
</taglib>

4. Page helper class

package com.ycxw.tag;

import com.ycxw.utils.PageBean;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
import java.io.IOException;
import java.util.Map;
import java.util.Set;

/**
 * Page助手类
 * 
 * @author 云村小威
 *
 */
public class PageTag extends BodyTagSupport {
	private static final long serialVersionUID = 1L;

	private PageBean pageBean;

	public PageBean getPageBean() {
		return pageBean;
	}

	public void setPageBean(PageBean pageBean) {
		this.pageBean = pageBean;
	}

	@Override
	public int doStartTag() throws JspException {
		// 获取流
		JspWriter out = pageContext.getOut();
		try {
			out.print(toHTML());
		} catch (IOException e) {
			e.printStackTrace();
		}
		return SKIP_BODY;
	}

	/**
	 * JSP自定义页面内容展示
	 * 
	 * @return
	 */
	private String toHTML() {
		StringBuilder sb = new StringBuilder();

		// 这里拼接的是一个上一次发送的请求以及携带的参数,唯一改变的就是页码
		sb.append("<form id='pageBeanForm' action='" + pageBean.getUrl() + "' method='post'>");
		sb.append("<input type='hidden' name='page'>");
		// 重要设置拼接操作,将上一次请求参数携带到下一次
		Map<String, String[]> paMap = pageBean.getParameterMap();
		if (paMap != null && paMap.size() > 0) {
			Set<Map.Entry<String, String[]>> entrySet = paMap.entrySet();
			for (Map.Entry<String, String[]> entry : entrySet) {
				for (String val : entry.getValue()) {
					if (!"page".equals(entry.getKey())) {
						sb.append("<input type='hidden' name='" + entry.getKey() + "' value='" + val + "'>");
					}
				}
			}
		}
		sb.append("</form>");
		
		/**
		 * 页码数据配置
		 */
		int page = pageBean.getPage(); //当前页码
		int max = pageBean.getMaxPage();//最大页码
		int before = page > 4 ? 4 : page - 1;//当前页码前面的页码
		int after = 10 - 1 - before;//当前页码后面的页码
		
		//如果最大页码没有10页,就显示当前页面后面的所有页码 max - page
		after = page + after > max ? max - page : after;
		// 初始页码和结束页码值判断 disabled
		boolean startFlag = page == 1;
		boolean endFlag = max == page;

		// 拼接分页条
		sb.append("<ul class='pagination'>");
		sb.append("<li class='page-item " + (startFlag ? "disabled" : "")
				+ "'><a class='page-link' href='javascript:gotoPage(1)'>首页</a></li>");
		sb.append("<li class='page-item " + (startFlag ? "disabled" : "")
				+ "'><a class='page-link' href='javascript:gotoPage(" + pageBean.getPrevPage() + ")'>&lt;</a></li>");

		// 代表了当前页的前4页
		for (int i = before; i > 0; i--) {
			sb.append("<li class='page-item'><a class='page-link' href='javascript:gotoPage(" + (page - i) + ")'>"
					+ (page - i) + "</a></li>");
		}

		sb.append("<li class='page-item active'><a class='page-link' href='javascript:gotoPage(" + pageBean.getPage()
				+ ")'>" + pageBean.getPage() + "</a></li>");

		// 代表了当前页的后5页
		for (int i = 1; i <= after; i++) {
			sb.append("<li class='page-item'><a class='page-link' href='javascript:gotoPage(" + (page + i) + ")'>"
					+ (page + i) + "</a></li>");
		}

		sb.append("<li class='page-item " + (endFlag ? "disabled" : "")
				+ "'><a class='page-link' href='javascript:gotoPage(" + pageBean.getNextPage() + ")'>&gt;</a></li>");
		sb.append("<li class='page-item " + (endFlag ? "disabled" : "")
				+ "'><a class='page-link' href='javascript:gotoPage(" + pageBean.getMaxPage() + ")'>尾页</a></li>");
		sb.append(
				"<li class='page-item go-input'><b>到第</b><input class='page-link' type='text' id='skipPage' name='' /><b>页</b></li>");
		sb.append("<li class='page-item go'><a class='page-link' href='javascript:skipPage()'>确定</a></li>");
		sb.append("<li class='page-item'><b>共" + pageBean.getTotal() + "条</b></li>");
		sb.append("</ul>");

		// 拼接分页的js代码
		sb.append("<script type='text/javascript'>");
		sb.append("function gotoPage(page) {");
		sb.append("document.getElementById('pageBeanForm').page.value = page;");
		sb.append("document.getElementById('pageBeanForm').submit();");
		sb.append("}");
		sb.append("function skipPage() {");
		sb.append("var page = document.getElementById('skipPage').value;");
		sb.append("if (!page || isNaN(page) || parseInt(page) < 1 || parseInt(page) > " + max + ") {");
		sb.append("alert('请输入1~N的数字');");
		sb.append("return;");
		sb.append("}");
		sb.append("gotoPage(page);");
		sb.append("}");
		sb.append("</script>");

		return sb.toString();
	}
}

5. BookServlet class

package com.ycxw.serlvet;

import java.io.IOException;
import java.util.List;

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 com.ycxw.dao.BookDao;
import com.ycxw.entity.Book;
import com.ycxw.utils.PageBean;

@WebServlet("/book.action")
public class BookServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doPost(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		BookDao bookDao = new BookDao();
		PageBean page = new PageBean();
		// 调用pageBean初始化方法
		page.setRequest(request);
		Book book = new Book();
		// 获取模糊查询字段值并设置到book对象中
		book.setBname(request.getParameter("bname"));
		try {
			// 调用BookDao模糊加分页查询方法
			List<Book> list = bookDao.list(book, page);
			// 将对象保存到作用域中
			request.setAttribute("books", list);
			request.setAttribute("pageBean", page);
			// 转发到分页界面
			request.getRequestDispatcher("/BookPage.jsp").forward(request, response);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

6. JSP page writing

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="com.ycxw" prefix="w"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!-- 导入bootstrap网络路径样式 -->
<link
	href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.css"
	rel="stylesheet">
<script
	src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/js/bootstrap.js"></script>
<title>书籍列表</title>
<style type="text/css">
.page-item input {
	padding: 0;
	width: 40px;
	height: 100%;
	text-align: center;
	margin: 0 6px;
}

.page-item input, .page-item b {
	line-height: 38px;
	float: left;
	font-weight: 400;
}

.page-item.go-input {
	margin: 0 10px;
}
</style>
</head>
<body>
	<form class="form-inline"
		action="${pageContext.request.contextPath }/book.action" method="post">
		<div class="form-group mb-2">
			<input type="text" class="form-control-plaintext" name="bname"
				placeholder="请输入书籍名称">
		</div>
		<button type="submit" class="btn btn-primary mb-2">查询</button>
	</form>

	<table class="table table-striped">
		<thead>
			<tr>
				<th scope="col">书籍ID</th>
				<th scope="col">书籍名</th>
				<th scope="col">价格</th>
			</tr>
		</thead>
		<tbody>
		<!-- 遍历数据 -->
			<c:forEach items="${books }" var="b">
				<tr>
					<td>${b.bid }</td>
					<td>${b.bname }</td>
					<td>${b.price }</td>
				</tr>
			</c:forEach>

		</tbody>
	</table>
	<!-- 自定义分页标签 -->
	<w:page pageBean="${pageBean }"></w:page>
</body>
</html>

7. Front-end interface display

Summarize:

        Universal paging is convenient for us to simplify the code, so we need to pack their common code. But when we are not familiar with it, we should ignore the encapsulation first, write out the paging first, and then extract the common part for encapsulation and inheritance. The general paging step is to first analyze the properties of the paging bar, then encapsulate the property entity, then write the dao layer method to extract the common part, and then write the paging assistant class. In order to avoid garbled characters, write a character filter to filter all requests. Finally, add the paging tag in the tag library description file, and you can use it according to your needs. The idea of ​​general paging is to extract the parts that can be extracted and then stitch them together for later calling.

Guess you like

Origin blog.csdn.net/Justw320/article/details/131413450