一、 需求描述
在JavaWeb开发中,分页是很常见的功能,在一个系统中,根据需求可能存在不同模块的分页,但是如果对每一个分页都写一个具体的类,这样做重复度太高,会造成代码冗余,因为分页处理的内容只不过是实体类型不同而已,其他的都大同小异。类型不同,自然想到Java泛型的类型参数,关于Java泛型,贴一篇不错的博客。
二、具体实现
- 首先,根据分页的功能需要抽象出一个泛型基类PageModel,该类应至少包含如下内容:
pageNumber: 代表是第几页,用户可以点击看指定的页码
pageSize: 用户可以指定每页显示多少数据
startRow: pageNumber和pageSize都是由与系统交互的使用用户设定的,实际去数据库查询的时候应指定从哪一行开始,startRow的值可以通过pageNumber和pageSize获取到!
queryObj:一个泛型类参数,用户在分页时往往是有查询条件的,通过queryObj封装查询对象,再对应的使用MyBatis的动态sql进行查询
rows: 查询结果返回的数据集
total: 分页时显示一共有多少条记录
综上,可以得到PageModel的泛型类为:
import java.util.List;
// 将分页的pageNumber和pageSize等有关的抽象出来,让具体业务有关的继承该类,同时具体的功能要有各自独立的部分!
// 注意这里使用了泛型!
public class PageModel<T> {
private Integer pageNumber = 1; //当前页数
private Integer pageSize = 10; //一页显示数量
private Integer startRow; //查询起始行
private Integer total; //总记录行数
// 泛型的使用!
private List<T> rows; //查询结果返回数据
private T queryObj; //查询对象
@Override
public String toString() {
return String.format("[pageNumber=%d, pageSize=%d]",
pageNumber, pageSize) ;
}
// pageNumber有-1的操作,可能会出现负值,所以需要进行整数判断!
public Integer getStartRow() {
if (pageNumber != null && pageSize != null && pageNumber >= 1) {
return (pageNumber - 1) * pageSize;
} else {
return 0;
}
}
public Integer getPageNumber() {
return pageNumber;
}
public void setPageNumber(Integer pageNumber) {
this.pageNumber = pageNumber;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public Integer getTotal() {
return total;
}
public void setTotal(Integer total) {
this.total = total;
}
public List<T> getRows() {
return rows;
}
public void setRows(List<T> rows) {
this.rows = rows;
}
public void setQueryObj(T queryObj) {
this.queryObj = queryObj;
}
public T getQueryObj() {
return queryObj;
}
public void setStartRow(Integer startRow) {
this.startRow = startRow;
}
}
- 根据业务需求设定具体的PageModel类
一个常见的需求是管理员查看当前系统中的用户,对他们进行某些操作,这个时候就需要分页了,此时除了PageModel中的属性外,也可以加上一些该类独有的属性。
public class UserPageModel<T> extends PageModel<T>{
private String curUserId;
public String getCurUserId() {
return curUserId;
}
public void setCurUserId(String curUserId) {
this.curUserId = curUserId;
}
}
Controller层:设定好查询的PageModel对象或其子类,同时设定好查询条件
用户分页的Controller层代码:
// 注意参数UserPageModel已经传入了User类参数!
@RequestMapping("listUserWithPageForJson.action")
@ResponseBody
public Map<String, Object> listUserWithPageForJson(HttpSession session, UserPageModel<User> userPageModel, User user) {
Map<String, Object> map = new HashMap<>();
// 封装查询条件
String userId = (String) session.getAttribute("userId");
user.setUserId(userId);
userPageModel.setQueryObj(user);
adminService.listUserWithPage(userPageModel);
map.put("total", userPageModel.getTotal());
map.put("rows", userPageModel.getRows());
map.put("userAccount", user.getUserAccount());
return map;
}
Service层:Service层是为Controller层服务的,在这里设定好查询返回的数据集对象和总的查询记录条数!
用户分页的Service层代码:
@Override
public void listUserWithPage(UserPageModel userPageModel) {
// 设定好rows和total
userPageModel.setRows(userDao.selectUserListWithPage(userPageModel));
userPageModel.setTotal(userDao.selectUserCountWithPage(userPageModel));
}
Dao层:Dao层是为Service层服务的,数据库查询返回具体的内容结果
用户分页的数据库查询代码
<select id="selectUserListWithPage" parameterType="com.shaogang.model.UserPageModel" resultMap="BaseResultMap">
select user.*, role.name, role.description from user, role
<where>
user.role_id = role.role_id
<if test="queryObj.userId != null">
AND user_id != #{queryObj.userId,jdbcType=VARCHAR}
</if>
<if test="queryObj.userAccount != null and queryObj.userAccount != ''">
And user_account like concat('%', #{queryObj.userAccount,jdbcType=VARCHAR}, '%')
</if>
</where>
order by register_time desc, login_time desc
<if test="pageNumber != null and pageSize!= null">
limit #{startRow},#{pageSize}
</if>
</select>
<select id="selectUserCountWithPage" parameterType="com.shaogang.model.UserPageModel" resultType="Integer">
select count(*) from user, role
<where>
user.role_id = role.role_id
<if test="queryObj.userId != null">
AND user_id != #{queryObj.userId,jdbcType=VARCHAR}
</if>
<if test="queryObj.userAccount != null and queryObj.userAccount != ''">
And user_account like concat('%', #{queryObj.userAccount,jdbcType=VARCHAR}, '%')
</if>
</where>
</select>
三、总结
泛型广泛用在设计模式和JDK容器类中,高级Java程序猿绝不是去写CRUD,而是应该思考如何写出“像诗一样优雅的"的代码!泛型的合理使用可以大大提高程序的灵活和可扩展性,减少重复、冗余代码!