后端处理分页请求的实现
通过层次化设计(Controller → Service → DAO),将功能解耦。使用工具类(Page)和查询对象(MtypeQuery)管理分页逻辑。利用 MyBatis 的动态 SQL 和公共片段提高代码复用性。验证输入参数(如pageNo和pageSize)的合法性,防止 SQL 注入。使用log记录分页查询的关键数据,便于调试和性能优化。
·
文章目录
1. 前端发送请求
- 请求路径:
/mtype/list
。 - 请求参数包括分页参数(
pageNo
、pageSize
)和查询条件(如tname
)。
2. 控制器层处理请求 (MtypeController
)
-
方法
listType(MtypeQuery mq, Model model)
:
- 首先判断是否传入
pageNo
参数,如果没有则默认为第 1 页。 - 调用
mtypeService.selectObjectByCondition(mq)
获取分页数据。 - 将结果存入
Model
中,供视图使用。 - 返回视图名称
"mtype"
。
- 首先判断是否传入
3. 服务层处理逻辑 (MtypeService
接口和实现)
-
接口
MtypeService
继承了BaseService
,提供分页查询的通用方法。 -
实现类
BaseServiceImpl
:
- 通过反射机制获取
pageNo
和计算startNum
。 - 调用
BaseDao
的selectObjectByCondition
和selectObjectByConditionCount
方法。 - 将查询结果和总记录数封装到
Page
对象中返回。
- 通过反射机制获取
4. 数据访问层处理数据 (BaseDao
接口和 MyBatis 配置)
-
BaseDao
定义了分页查询和统计的通用方法。 -
MyBatis XML 文件中:
-
查询数据的 SQL (
selectObjectByCondition
):
- 根据条件拼接 SQL(例如
tname
条件)。 - 使用
<include>
引用公共分页 SQL (limit #{startNum}, #{pageSize}
)。
- 根据条件拼接 SQL(例如
-
查询记录数的 SQL (
selectObjectByConditionCount
):
- 仅返回总记录数,未分页。
-
使用动态 SQL (
<if>
和<where>
) 构造灵活的查询条件。
-
5. 工具类支持 (Page
类)
-
Page
类封装了分页信息,包括:
- 每页记录数(
pageSize
)。 - 当前页码(
pageNo
)。 - 总记录数(
totalCount
)。 - 总页数(
totalPage
)。 - 起始记录号(
startNum
)。 - 当前页的数据集合(
list
)。
- 每页记录数(
-
提供方法自动计算
startNum
和totalPage
。
6. 数据模型和查询对象
Mtype
:实体类,表示数据库表mtype
中的一条记录。MtypeQuery
:查询对象,继承Mtype
并添加分页参数,提供自动计算startNum
的功能。
7. 数据库交互
- 表结构假设包含字段
tid
和tname
。 - 查询条件可根据
tname
进行模糊搜索。 - 分页功能通过
limit
实现。
8.代码区
BaseDao:
package cn.tx.dao;
import java.util.List;
/**
*持久层的向上提取
* 提取共同的Base持久层接口
* 基础CURD操作
* @param <T>
*/
public interface BaseDao<Q,T> {
List<T> selectObjectByCondition(Q q);
int selectObjectByConditionCount(Q q);
}
MtypeQuery
package cn.tx.query;
import cn.tx.model.Mtype;
public class MtypeQuery extends Mtype {
private Integer pageNo = 1; // 默认第一页
private Integer pageSize = 5; // 默认每页 5 条
private Integer startNum; // 开始记录数由计算得出
public Integer getPageNo() {
return pageNo;
}
public void setPageNo(Integer pageNo) {
this.pageNo = pageNo == null || pageNo < 1 ? 1 : pageNo; // 确保页码有效
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize == null || pageSize < 1 ? 5 : pageSize; // 确保每页记录数有效
}
public Integer getStartNum() {
return (pageNo - 1) * pageSize; // 自动计算开始记录数
}
public void setStartNum(Integer startNum) {
this.startNum = startNum;
}
}
BaseServiceImpl
package cn.tx.service.Impl;
import cn.tx.dao.BaseDao;
import cn.tx.service.BaseService;
import cn.tx.util.Page;
import java.lang.reflect.Method;
import java.util.List;
public class BaseServiceImpl<Q,T> implements BaseService<Q,T> {
/**
* 如何注入BaseDao的值
* 如何决定? 可以支持两次注入,但是不好
* 选择使用java基础的权限修饰符
* 以及set方法注入的形式改为一次注入
*/
protected BaseDao<Q,T> baseDao;
// 注入 BaseDao
@Override
public Page<T> selectObjectByCondition(Q q) {
//获得查询对象的类对象
Class<? extends Object> qclass = q.getClass();
Page<T> page = new Page<T>();
try {
//获得getPageNo对象
Method method = qclass.getMethod("getPageNo", null);
//反射调用getPageNo方法
Integer pageNo = (Integer) method.invoke(q, null);
//创建page对象
page.setPageNo(pageNo);
//计算开始行号和结束行号
int startNum = page.getStartNum();
//好的查询对象 的设置开始行号和结束行号的方法
Method setStartNumMethod = qclass.getMethod("setStartNum", new Class[]{int.class});
setStartNumMethod.invoke(q, startNum);
} catch (Exception e) {
e.printStackTrace();
}
//查询结果集
List<T> list = baseDao.selectObjectByCondition(q);
//查询指定查询条件下的总记录数
int count = baseDao.selectObjectByConditionCount(q);
//把总记录数设置给page对象
page.setTotalCount(count);
page.setList(list);
return page;
}
}
BaseService
package cn.tx.service;
import cn.tx.util.Page;
/**
*业务层的向上提取
* 提取共同的Base业务层接口
* 基础CURD操作
* @param <T>
*/
public interface BaseService<Q,T> {
//根据ID列进行删除
int deleteByPrimaryKey(Integer tid);
//添加数据的接口
int insert(T t);
//根据ID进行查询某一个数据
T selectByPrimaryKey(Integer tid);
//更新修改根据ID进行
int updateByPrimaryKey(T t);
/**
* 分页查询
* @param
* @return
*/
public Page<T> selectObjectByCondition(Q q);
}
page
package cn.tx.util;
import java.util.List;
public class Page<T> {
/**
* 每页记录数(已知)
*/
private int pageSize = 5;
/**
* 页码(已知)
*/
private int pageNo = 1;
/**
* 指定查询条件下的总记录数(已知)
*/
private int totalCount = 0;
/**
* 指定查询条件下 的总页数
*/
private int totalPage = 1;
/**
* 使用sql查询的时候的开始行号
*/
private int startNum = 0;
/**
* 结果集
*/
private List<T> list;
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getPageNo() {
return pageNo;
}
public void setPageNo(int pageNo) {
this.pageNo = pageNo;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
/**
*
*
* totalCount pageSize totalPage
* 0 10 1
* 55 10 6
* 100 10 10
* @return
*/
public int getTotalPage() {
totalPage = totalCount/pageSize;
if(totalCount == 0 || totalCount%pageSize != 0){
totalPage++;
}
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public int getStartNum() {
return (pageNo -1 )*pageSize;
}
public void setStartNum(int startNum) {
this.startNum = startNum;
}
public List<?> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
}
MtypeMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.tx.dao.MtypeMapper">
<sql id="page">
limit #{startNum}, #{pageSize}
</sql>
<select id="selectObjectByCondition" parameterType="cn.tx.query.MtypeQuery" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from mtype
<where>
<if test="#{tname} != null">
tname like '%${tname}%'
</if>
</where>
<include refid="page" />
</select>
<select id="selectObjectByConditionCount" parameterType="cn.tx.query.MtypeQuery" resultType="int">
select
count(*)
from mtype
<where>
<if test="#{tname} != null">
tname like '%${tname}%'
</if>
</where>
</select>
</mapper>
MtypeController
package cn.tx.controller;
import cn.tx.model.Mtype;
import cn.tx.util.Page;
import cn.tx.query.MtypeQuery;
import cn.tx.service.MtypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 流派业务的表现层类
* 处理前端页面的请求
*/
@Controller
@RequestMapping("/mtype")
public class MtypeController {
/**
* 流派的分页条件查询
* @return
*/
@Autowired
private MtypeService mtypeService;
@RequestMapping("/list")
public String listType(MtypeQuery mq, Model model){
if(mq.getPageNo() == null){
mq.setPageNo(1);
}
Page<Mtype> page = mtypeService.selectObjectByCondition(mq);
model.addAttribute("page", page);
return "mtype";
}
}
9.总结
这一流程的核心是:
- 通过层次化设计(Controller → Service → DAO),将功能解耦。
- 使用工具类(
Page
)和查询对象(MtypeQuery
)管理分页逻辑。 - 利用 MyBatis 的动态 SQL 和公共片段提高代码复用性。
如需进一步优化,建议:
- 验证输入参数(如
pageNo
和pageSize
)的合法性,防止 SQL 注入。 - 使用
log
记录分页查询的关键数据,便于调试和性能优化。
更多推荐
所有评论(0)