目录
一、介绍
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开发者而言是非常有价值的,它可以从多个方面提高开发效率,优化用户体验,提升系统性能,并降低服务器的负荷,大大提高了软件的开发和使用效率。