一、介绍
1.通用分页是什么
JavaEE通用分页,即将数据分页展示的一种通用方式。在JavaEE开发中,通常会涉及到数据展示的需求,例如查询数据库中的数据并展示到网页中。但是,当数据量很大时,一次性展示所有数据会影响页面的加载速度和性能,因此需要将数据分页展示。通用分页是指通过一定的规则将数据按页码进行划分,并且提供对每一页数据的访问方式,从而实现数据的分页展示。
在JavaEE中,常用的分页方式是在数据查询时,在SQL语句中使用limit关键字进行限制。具体实现方式是通过计算总记录数和每页展示的记录数,将需要的记录分割成若干页,并提供访问对应页码数据的方法。此外,也可以使用JavaEE框架中提供的分页工具类,如Spring分页插件,方便快速地实现通用分页功能。
2.为什么要学
学习JavaEE中通用分页功能是非常有必要的,因为在实际的Web应用程序开发中,经常需要处理大量数据。在这种情况下,一次从数据源中检索所有记录的操作会导致长时间的等待,浪费大量的时间和资源。此外,如果数据量较大,还可能会造成单次查询异常或内存溢出等问题。
因此,在JavaEE中实现通用分页功能是一个非常普遍的解决方案,这将大大提高Web应用程序的性能和体验。通用分页也可以帮助我们更好地处理业务求,因为用户经常需要在多个页面之间跳转,同时保持分页状态。掌握通用分页功能,可以使我们更加熟练和高效地编写代码,提高我们作为JavaEE开发人员的技能水平。
3.怎么用
在MySQL中使用JavaEE中通用分页功能,通常需要以下步骤:
1.按照要求编写 SQL 语句,在 SQL 语句的末尾增加 LIMIT 关键字,用于限制查询结果的范围。例如,使用 LIMIT 子句限制查询结果从第 1 行开始,取出100条数据的 SQL 语句如下:
SELECT * FROM 表名 WHERE 条件 LIMIT 0,100;
其中,0 表示查询结果的起始行数,100 表示查询结果的数量。
2.在 JavaEE 的业务逻辑层中使用查询语句查询数据,并且获取分页参数(如当前页码、每页数据量等),计算当前数据查询需要使用的 LIMIT 语句的两个参数(即上面步骤中的起始行数和每页数量)。
3.将得到的起始行数和每页数量拼接到 SQL 语句中,形成可以直接使用的 SQL 语句。可以利用占位符,将分页参数插入到 SQL 语句中,以防止 SQL 注入等问题。
4.使用 JDBC 等数据访问框架执行带有 LIMIT 子句的 SQL 语句获取对应的分页数据,将其封装成 Java 对象。
5.在业务逻辑层中,根据查询结果和分页参数,封装一个分页对象,将查询结果和分页对象一起返回到展示层,供前端页面进行展示。
6.前端展示分页数据通常需要使用 JavaScript 等前端技术,根据获取到的分页对象数据,在页面上生成分页控制器,然后将查询到的数据进行展示。
以上就是在 MySQL 数据库中使用 JavaEE 中通用分页功能的基本流程,同样需要注意业务需求和框架的差异,处理方式也会有所不同。为避免一些潜在的问题和安全隐患,应该注意合理设计 SQL 语句、使用有效的数据访问框架以及数据分页的相关参数,以提高对分页查询的使用体验和安全性。
二、不使用通用
JavaWeb分页功能的主要流程如下:
1. 用户请求分页:通常是通过前端页面向后端发起一个HTTP/GET请求,将分页相关参数(当前页码、每页展示数量等)以请求参数的形式传递给后端。
2. 查询总记录数:根据用户请求,后端通过SQL语句查询数据库,获取需要展示的总记录数。这个操作通常是用COUNT函数实现,可以提高查询效率。
3. 计算分页信息:后端根据总记录数和用户请求,计算出展示的总页数和当前页码,同时计算出查询数据的起始位置和截止位置。
4. 查询当前页数据:后端再次根据用户请求,通过SQL语句查询数据库,获取当前页需要展示的数据。查询语句加上LIMIT关键字,根据计算出的数据范围进行分页查询。
5. 返回分页数据:后端将查询出的数据和分页相关信息打包返回给前端,通常是以JSON格式返回,前端通过解析JSON数据并展示到页面上。
6. 前端分页展示:前端负责将后端返回的数据进行渲染展示,同时渲染出分页控制器。用户可以通过控制器切换页码和设定每页展示的数量。
7. 重新发起分页请求:如果用户对分页控制器进行了操作,前端将重新发起分页请求,并将分页相关参数再次传递给后端进行查询。
以上就是JavaWeb分页功能的基本流程。分页作为一个基础而常用的功能,在实际应用中经常会出现,因此掌握分页技术是比较有价值的一项技能。
1.增加数据表及数据
1.1创建表
如果要在 MySQL 中增加一个数据表,并设置属性 bid、bname、price,可以使用以下 SQL 语句:
CREATE TABLE t_mvc_book( bid INT PRIMARY KEY AUTO_INCREMENT, bname VARCHAR(100), price FLOAT );
其中,t_mvc_book
是数据表名,bid
、bname
、price
分别是列名,INT
、VARCHAR
、FLOAT
分别是数据类型,PRIMARY KEY
表示设置主键,AUTO_INCREMENT
表示主键自动递增。这样就创建好了一个名为 books 的数据表,有三个列,分别是 bid,bname 和 price。
1.2增加数据
如果需要向 books 表中插入数据,可以使用 INSERT INTO 语句,语法如下:
INSERT INTO t_mvc_book(bname, price) VALUES ('斗破苍穹', 78.00);
以上语句会向 t_mvc_book表中插入一条新纪录,包含 bname 和 price 两个属性,其中 bname 属性对应的值为 ‘斗破苍穹’,price 属性对应的值为 78.00。如果还需要向表中插入更多的数据记录,只需要在语句选择的列中添加对应记录的值即可。
需要注意的是,数据表属性的命名规范、数据类型的选择、主键、外键等的设置,以及插入数据时的数据格式、字符编码等都是需要考虑的问题,需要根据具体业务需求进行设置和调整,以提高数据表的可维护性和使用的效率
2.mysql连接类
2.1辅助文件
#mysql driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis_ssm?useUnicode=true&characterEncoding=UTF-8&useSSL=false user=root pwd=123456
2.2连接类
package com.CloudJun.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 Cloud.Jun * @com.CloudJun.utils * @DBAccess(说明):提供了一组获得或关闭数据库对象的方法 */ 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("数据库连接(关闭)成功"); } }
3.工具(帮助)类
3.1帮助类
StringUtils类
package com.CloudJun.utils; /** * @author Cloud.Jun * @com.CloudJun.utils * @StringUtils(说明):帮助类 */ 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); } }
3.2工具类
PageBean类
package com.CloudJun.utils; /** * @author Cloud.Jun * @com.CloudJun.utils * @PageBean(说明):分页工具类 */ 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 + "]"; } }
4.实体类
Book类
package com.CloudJun.entity; /** * @author Cloud.Jun * @com.CloudJun.entity * @Book(说明):书(实体类) */ 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(int bid, String bname, float price) { super(); this.bid = bid; this.bname = bname; this.price = price; } public Book() { super(); } }
5.数据访问层
package com.CloudJun.dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import org.junit.Test; import com.CloudJun.entity.Book; import com.CloudJun.utils.DBAccess; import com.CloudJun.utils.PageBean; import com.CloudJun.utils.StringUtils; /** * @author Cloud.Jun * @com.CloudJun.dao * @BookDao(说明):Book的模糊查询方法类 */ public class BookDao { public List<Book> getlist(Book b, PageBean pb) throws Exception { // 实例化集合为容器,装载返回接收的数据 List<Book> list = new ArrayList<Book>(); // 进行mysql数据库连接 Connection conn = DBAccess.getConnection(); // 定义sql语句 String sql = "select * from t_mvc_book where 1=1 "; // 当关键词不为空的时候,拼接模糊查询的sql语句 String bname = b.getBname(); if (StringUtils.isNotBlank(bname)) { sql += " and bname like '%" + bname + "%'"; } // 执行sql语句 PreparedStatement pr = conn.prepareStatement(sql); // 返回所执行后的结果 ResultSet rs = pr.executeQuery(); while (rs.next()) { // 将结果集加入实体 Book book = new Book(rs.getInt(1), rs.getString(2), rs.getFloat(3)); // 将实体加入list集合 list.add(book); } if (list != null) { DBAccess.close(conn, pr, rs); } return list;// 最后返回容器(集合) } @Test public void Text() throws Exception { Book book = new Book(); book.setBname("圣墟"); PageBean pb = new PageBean(); List<Book> list = new BookDao().getlist(book, pb); for (Book bo : list) { System.out.println(bo); } } }
6.测试结果
以下测试结果由本人自己加入了数据
三、JUnit4
3.1什么?
JUnit 是一个用于测试 Java 代码的测试框架,JUnit4 是 JUnit 框架的一个重要版本。JUnit4 是一个开源框架,可以帮助程序员进行单元测试,在程序的开发阶段可以在系统没有完成前发现问题,从而缩小了错误的范围,更好地实现了敏捷开发的目标。
JUnit4 提供了大量的注解、API 等功能,使用起来比较方便。JUnit4 的主要特点包括:
1. 基于注解:JUnit4 主要使用注解来标识测试方法和测试类,使用起来比较简单。
2. 易于使用:JUnit4 设计简洁,可以帮助用户快速编写和运行测试用例。
3. 灵活性:JUnit4 具有比较高的灵活性,可以完成多种测试任务,包括单元测试、集成测试和功能测试等。
4. 多用途性:JUnit4 不仅可以用于 Java 项目,还可以用于其他语言的测试中。
5. 多平台支持:JUnit4 可以运行在多个平台(如 Windows、Linux、Mac OS X 等)上,可以为不同的项目提供测试支持。
6. 不需要持久化:JUnit4 测试用例运行在内存中,并不需要数据库或文件操作等持久化操作。
熟练掌握使用 JUnit4 进行单元测试可以极大的提高程序开发和测试效率,不仅可以减少软件开发所需时间、增加交付速度,更可以提升软件的稳定性和可靠性。
3.2引入
在 Eclipse 中引入 JUnit4 项目,可以按照以下步骤进行:
- 下载 JUnit4:从 JUnit 官方网站或 Maven 仓库中下载 JUnit4 相应的 jar 包,或者通过 Maven 或 Gradle 等项目构建工具引入。
- 导入 JUnit4 文件:在 Eclipse 中,点击 File -> Import,选择 General -> Existing Projects into Workspace,然后选择下载的 JUnit4 jar 包所在的目录,导入到项目中。
- 将 JUnit4 加入到项目中的 Build Path:在 Eclipse 中,选择 Project -> Properties,然后在左侧导航栏中点击 Java Build Path,选择 Libraries 选项卡,点击右侧 Add Library 按钮,选择 JUnit4,然后点击 Finish 完成添加。
- 编写测试用例:在创建的测试类中编写测试方法,并使用 JUnit4 提供的注解标注测试方法,如使用
@Test
在测试类中指定测试方法。 - 主要如图操作:
选中要导入的项目名称右键
之后Finish到底即可
3.3使用
将要测试的方法打上@Test之后选中方法名右键测试即可,如图:
四、使用通用
需要进行通用先建一个类叫BaseDao类该类由通用分页的方法功能,在进行修改BookDao类,在该类里面进行测试
4.1 BaseDao类
package com.CloudJun.dao; 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.CloudJun.utils.DBAccess; import com.CloudJun.utils.PageBean; /** * @author Cloud.Jun * @com.CloudJun.dao * @BaseDao(说明):通用的分页方法功能类 */ public class BaseDao<T> { public List<T> executeQuery(String sql,Class c,PageBean pb) throws Exception{ //实例化集合为容器,装载返回接收的数据 List<T> list = new ArrayList<T>(); //定义连接对象 Connection conn = null; //执行对象 PreparedStatement pr = null; //结果集对象 ResultSet rs = null; //判断是否分页,为null或者为""都是不进行分页 if(pb.isPagination() && pb!=null) { //获取查询总数量(数据)后的sql语句 String count= getCount(sql); //进行mysql数据库连接 conn=DBAccess.getConnection(); //执行sql语句 pr= conn.prepareStatement(count); //返回所执行后的结果集 rs=pr.executeQuery(); //将总记录数赋值给分页工具类 if(rs.next()) { pb.setTotal(rs.getObject("n").toString()); } //初始下标,从哪里开始(从第几条数据开始) String pagesize=getPagesize(sql,pb); //进行mysql数据库连接 conn=DBAccess.getConnection(); //执行sql语句 pr= conn.prepareStatement(pagesize); //返回所执行后的结果集 rs=pr.executeQuery(); }else { //进行mysql数据库连接 conn=DBAccess.getConnection(); //执行sql语句 pr = conn.prepareStatement(sql); //返回所执行后的结果 rs = pr.executeQuery(); } //循环集合集 while(rs.next()) { //进行反射(通过类名获取实例对象) T t = (T) c.newInstance(); //返回该类中所有的变量(属性),不包括继承的成员变量和静态变量。 Field[] fields = c.getDeclaredFields(); //循环所有变量(属性) for (Field field : fields) { //打开变量的私有权限 field.setAccessible(true); //设置属性值(获取该对象[t]的属性,根据field.getName()的方法获取该对象属性名称后进行属性值赋值) field.set(t, rs.getObject(field.getName())); } //增加进容器(集合) list.add(t); } return list;//最后返回容器(集合) } /** * 方法功能:计算分页显示多少条数据 * @param sql 根据传过来的sql语句再进行条件查询 * @param pb 分页工具类 * @return */ public String getPagesize(String sql, PageBean pb) { return sql + " LIMIT "+pb.getStartIndex()+","+pb.getRows(); } /** * @param sql 查询传过来的sql语句再进行查询总数据条数(总记录) * @return 查询总数量的sql语句 */ public String getCount(String sql) { return "SELECT COUNT(1) as n from("+sql+") t"; } }
4.2 BookDao
package com.CloudJun.dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import org.junit.Test; import com.CloudJun.entity.Book; import com.CloudJun.utils.DBAccess; import com.CloudJun.utils.PageBean; import com.CloudJun.utils.StringUtils; /** * @author Cloud.Jun * @com.CloudJun.dao * @BookDao(说明):Book的模糊查询方法类 */ public class BookDao extends BaseDao<Book>{ public List<Book> getlist(Book b, PageBean pb) throws Exception { // 实例化集合为容器,装载返回接收的数据 List<Book> list = new ArrayList<Book>(); // 进行mysql数据库连接 Connection conn = DBAccess.getConnection(); // 定义sql语句 String sql = "select * from t_mvc_book where 1=1 "; // 当关键词不为空的时候,拼接模糊查询的sql语句 String bname = b.getBname(); if (StringUtils.isNotBlank(bname)) { sql += " and bname like '%" + bname + "%'"; } // 执行sql语句 PreparedStatement pr = conn.prepareStatement(sql); // 返回所执行后的结果 ResultSet rs = pr.executeQuery(); while (rs.next()) { // 将结果集加入实体 Book book = new Book(rs.getInt(1), rs.getString(2), rs.getFloat(3)); // 将实体加入list集合 list.add(book); } if (list != null) { DBAccess.close(conn, pr, rs); } return list;// 最后返回容器(集合) } @Test public void Text() throws Exception { Book book = new Book(); book.setBname("圣墟"); PageBean pb = new PageBean(); List<Book> list = new BookDao().getlist(book, pb); for (Book bo : list) { System.out.println(bo); } } public List<Book> BaseDaoText(Book book,PageBean pb) throws Exception { // 定义sql语句 String sql = "select * from t_mvc_book where 1=1 "; // 当关键词不为空的时候,拼接模糊查询的sql语句 String bname = book.getBname(); if (StringUtils.isNotBlank(bname)) { sql += " and bname like '%" + bname + "%'"; } return executeQuery(sql, book.getClass(), pb); } @Test public void Text2() throws Exception { Book book = new Book(); book.setBname("圣墟"); PageBean pb = new PageBean(); //测试是否分页 // pb.setPagination(false); //测试显示在页面多少条 // pb.setRows(20); //测试初始页码 // pb.setPage(2); List<Book> list = new BookDao().BaseDaoText(book, pb); for (Book bo : list) { System.out.println(bo); } } }
4.3 测试结果
1.测试页面只显示20条
2.测试初始页面为第2页
3.不进行分页
对我们带来什么
JavaEE(Java Enterprise Edition) 通用分页可以帮助我们在开发 JavaEE 项目时更方便地实现数据分页效果,从而提高了用户的体验和系统的性能。通用分页的好处有以下几点:
1. 提高数据的查询效率:随着我们的数据量增加,查询数据的耗时也会越来越长。使用分页后,每次只查询一页的数据,减少了一次查询的数据量,从而减少了查询的耗时,使数据分页的效果更加明显。
2. 提升用户体验:通过数据分页,可以使用户可以更方便快捷地浏览到数据,更好地满足用户的需求,提升用户的体验。
3. 减少服务器压力:在没有使用分页的情况下,每次查询都是全部数据,在数据量大的情况下,我们的服务器压力非常巨大,而使用数据分页后,每次查询只是需要查询一页的数据,减少了服务器的压力,同时也降低了数据传输的开销。
4. 方便管理和维护:使用通用分页,我们可以通过简单的代码对分页进行控制和管理,方便了代码的维护和修改。
5. 提升应用程序性能:在许多情况下,数据分页可以在应用程序中提高性能和响应时间,从而增强了应用程序的性能。
综上所述,JavaEE的通用分页对于JavaEE开发者而言是非常有价值的,它可以从多个方面提高开发效率,优化用户体验,提升系统性能,并降低服务器的负荷,大大提高了软件的开发和使用效率。