1.什么是通用分页
通用分页是一种在Java Web开发中广泛使用的技术,它用于处理大量数据并将它们分成多个页面进行显示。通用分页通常包括一个分页组件和分页查询方法,该方法使用分页参数查询并返回指定页面和指定数量的数据结果。通常可以设置每页显示的数据数量,当前页面的页码以及总共的数据数量等。
通用分页的主要目的是为了更方便地浏览并处理大量数据。使用通用分页可以减轻服务器负担,提高数据处理效率和页面加载速度,同时也能使数据更加直观和易于管理。在开发中,通用分页通常会配合前端框架一起使用,以实现更好的用户体验。
2.反射完成通用的查询功能
编写一组获得或关闭数据库对象的方法:
package com.xiaoye.util; 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; /** * 提供了一组获得或关闭数据库对象的方法 * */ 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("数据库连接(关闭)成功"); } }
编写一个能够连接数据库的方法:
编写一个私有的构造方法:
package com.xiaoye.util; 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); } }
编写一个分页工具类:
package com.xiaoye.util; /** * 分页工具类 * */ 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 + "]"; } }
编写一个过滤器(凡是被过滤器处理的都变成了 中文乱码处理):
package com.xiaoye.util; 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; /** * 过滤器 * 凡是被过滤器处理的都变成了 中文乱码处理 * */ 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(); } } }
编写实体类BOOK:
package com.xiaoye.entity; 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; } }
编写BookDao :
public List<Book> list1(Book book, PageBean bean) throws Exception { List<Book> list = new ArrayList<Book>(); Connection conn = DBAccess.getConnection(); String sql = "select * from t_mvc_book where 1=1"; String bname = book.getBname(); // 判断bname不为空的情况下才进行 if (StringUtils.isNotBlank(bname)) { sql += " and bname LIKE '%" + bname + "%'"; } PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery(); while (rs.next()) { Book b = new Book(); b.setBid(rs.getInt("bid")); b.setBname(rs.getString("bname")); b.setPrice(rs.getFloat("price")); l.add(b); } return l; }
输出结果:
编写basedao:
代码重复:必须要写的
Connection conn = DBAccess.getConnection(); PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery();
流程重复:
创建表对应的实体类对象,将查询出来的结果集添加到实例化对象的属性中,已经被填充的实体对象,加入到集合中
Book b=new Book(); b.setBid(rs.getInt("bid")); b.setBname(rs.getString("bname")); b.setPrice(rs.getFloat("price")); l.add(b);
创建一个basedao泛型basedao:
package com.xiaoye.util; 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; import com.xiaoye.entity.Book; public class BaseDao<T> { public List<T> executeQuery(String sql,Class clz,PageBean p) throws Exception{ List<T> list = new ArrayList<T>(); Connection conn = DBAccess.getConnection(); PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery(); while(rs.next()) { T t = (T) clz.newInstance(); //拿到clz对应的所有属性对象 Field[] fields = clz.getDeclaredFields(); for (Field f : fields) { f.setAccessible(true);//打开访问权限 f.set(t, rs.getObject(f.getName())); } list.add(t); } return list; } }
到BOOKDAO进行代码测试:
public List<Book> list2(Book book,PageBean pegeBean) throws Exception{ String sql ="select * from t_mvc_book where 1=1"; String bname = book.getBname(); if(StringUtils.isNotBlank(bname)) { sql +=" and bname like '%"+bname+"%'"; } return super.exrcuteQuery(sql, Book.class, pegeBean); }
使用main方法测试:
public static void main(String[] args) throws Exception { BookDao bookDao=new BookDao(); Book book=new Book(); book.setBname("圣墟"); PageBean pageBen=new PageBean(); List<Book> list = bookDao.list(book, pageBen); for (Book b : list) { System.out.println(b); } }
输出结果:
4.junit单元测试:
JUnit是一个Java语言的单元测试框架,用于编写和运行自动化测试,JUnit提供了测试框架,用于测试Java代码的各种方面,包括方法的返回值和异常处理
在bookDao里面建立两个test:
@Test public void test() throws Exception { System.out.println("test1.."); BookDao bookDao=new BookDao(); Book book=new Book(); book.setBname("圣墟"); PageBean pageBen=new PageBean(); List<Book> list = bookDao.list1(book, pageBen); for (Book b : list) { System.out.println(b); } } @Test public void test2() throws Exception { System.out.println("test2.."); BookDao bookDao=new BookDao(); Book book=new Book(); book.setBname("圣墟"); PageBean pageBen=new PageBean(); List<Book> list = bookDao.list2(book, pageBen); for (Book b : list) { System.out.println(b); } }
输出结果:
5.通用查询带分页:
在BaseDAO里面写两个方法:pegeBean sql
package com.xiaoye.util; 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; import com.xiaoye.entity.Book; public class BaseDao<T> { /** * * @param sql * @param c Book.class * @param pegeBean * @return * @throws Exception */ public List<T> exrcuteQuery(String sql,Class c,PageBean pegeBean) throws Exception{ List<T> l=new ArrayList<T>(); Connection con = null; PreparedStatement ps = null; ResultSet rs = null; if(pegeBean !=null && pegeBean.isPagination()) { String countSQL=getCountSQL(sql); con=DBAccess.getConnection(); ps = con.prepareStatement(countSQL); rs = ps.executeQuery(); if(rs.next()) { pegeBean.setTotal(rs.getObject("n").toString()); } String pageSQL=getPageSQL(sql,pegeBean); con=DBAccess.getConnection(); ps = con.prepareStatement(pageSQL); rs = ps.executeQuery(); }else { con=DBAccess.getConnection(); ps = con.prepareStatement(sql); rs = ps.executeQuery(); } while(rs.next()) { T t=(T) c.newInstance(); //拿到class对应的使用对象 Field[] fields = c.getDeclaredFields(); for (Field f : fields) { f.setAccessible(true); // System.out.println(f.getName()); f.set(t, rs.getObject(f.getName())); } l.add(t); } return l; } /** * 拼接出最终展示出的数据sql * @param sql 原生sql * @param pegeBean * @return */ private String getPageSQL(String sql, PageBean pegeBean) { return sql+" limit "+pegeBean.getStartIndex()+","+pegeBean.getRows(); } /** * 拼接出查询符合条件的总记录sql * @param sql * @return */ private String getCountSQL(String sql) { return "SELECT count(1) as n from ("+sql+") t"; } }
然后在BookDao里面在写一个Test:
@Test public void test3() throws Exception { System.out.println("test3.."); BookDao bookDao=new BookDao(); Book book=new Book(); book.setBname("圣墟"); PageBean pageBen=new PageBean(); //不需要分页 // pageBen.setPagination(false); //查询第二页的数据 // pageBen.setPage(2); List<Book> list = bookDao.list2(book, pageBen); for (Book b : list) { System.out.println(b); } System.out.println(pageBen); }
输出结果:
不需要分页:
pageBen.setPagination(false);
输出结果:
查询第二页的数据:
pageBen.setPage(2);
输出结果:
没有用以上两种方法:
@Test public void test3() throws Exception { System.out.println("test3.."); BookDao bookDao=new BookDao(); Book book=new Book(); book.setBname("圣墟"); PageBean pageBen=new PageBean(); //不需要分页 // pageBen.setPagination(false); //查询第二页的数据 // pageBen.setPage(2); List<Book> list = bookDao.list2(book, pageBen); for (Book b : list) { System.out.println(b); } System.out.println(pageBen); }
输出结果:
动起来你们的双手