前言 :
在实际java web项目 开发过程中,由于需要展示的数据很多我们常常要用到分页功能,特别是针对不同数据表的分页,我们需要写许多重复的代码,所有我们设计一个通用分页功能,该方法能对象不同数据表进行分页,从而简化代码,提高开发效率。
一、封装工具类
1. 分析数据
1. 首先根据需求要从哪里拿数据,这里一MySql为例
2. 定义需要的sql语句
3. 需知需要展示的内容封装的对象,是否有多个
4. 根据原生分页,简化代码
4. 找到共同特点,重复的代码进行封装
2. 数据库配置文件
这里封装了四个不同数据库的连接数据,可根据自身电脑配置修改数据(该文件叫)
#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. 数据库帮助类
这里提供了一组获得或关闭数据库对象的方法,它会读取数据库配置文件,如上 (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. 字节码过滤器
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. 字符串判空类
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. 分页工具类
这里定义了四个属性 页码、展示数据条数、总记录数和是否分页,可根据需求进行增改
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 + "]"; } }
二、通用分页实例(后端)
1. 定义数据对象
这里只编写一个实体进行测试,以book为例
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. 原生dao层查询方法
该方法查询到所有数据
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分页方法
根据查询方法进行优化:
- 将重复的代码进行封装,如数据连接、执行SQL等
- 利用泛型加反射动态操作数据,因为将来可能有多个数据表的数据不可每个都要写一个方法
- 调用pageBean工具类进行分页操作
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分页方法
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. 后端数据测试
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); } } }
运行结果: