1. 前端发送请求

  • 请求路径:/mtype/list
  • 请求参数包括分页参数(pageNopageSize)和查询条件(如 tname)。

2. 控制器层处理请求 (MtypeController)

  • 方法

    listType(MtypeQuery mq, Model model)
    

    • 首先判断是否传入 pageNo 参数,如果没有则默认为第 1 页。
    • 调用 mtypeService.selectObjectByCondition(mq) 获取分页数据。
    • 将结果存入 Model 中,供视图使用。
    • 返回视图名称 "mtype"

3. 服务层处理逻辑 (MtypeService 接口和实现)

  • 接口 MtypeService 继承了 BaseService,提供分页查询的通用方法。

  • 实现类

    BaseServiceImpl
    

    • 通过反射机制获取 pageNo 和计算 startNum
    • 调用 BaseDaoselectObjectByConditionselectObjectByConditionCount 方法。
    • 将查询结果和总记录数封装到 Page 对象中返回。

4. 数据访问层处理数据 (BaseDao 接口和 MyBatis 配置)

  • BaseDao 定义了分页查询和统计的通用方法。

  • MyBatis XML 文件中:

    • 查询数据的 SQL (

      selectObjectByCondition
      

      ):

      • 根据条件拼接 SQL(例如 tname 条件)。
      • 使用 <include> 引用公共分页 SQL (limit #{startNum}, #{pageSize})。
    • 查询记录数的 SQL (

      selectObjectByConditionCount
      

      ):

      • 仅返回总记录数,未分页。
    • 使用动态 SQL (<if><where>) 构造灵活的查询条件。


5. 工具类支持 (Page 类)

  • Page
    

    类封装了分页信息,包括:

    • 每页记录数(pageSize)。
    • 当前页码(pageNo)。
    • 总记录数(totalCount)。
    • 总页数(totalPage)。
    • 起始记录号(startNum)。
    • 当前页的数据集合(list)。
  • 提供方法自动计算 startNumtotalPage


6. 数据模型和查询对象

  • Mtype:实体类,表示数据库表 mtype 中的一条记录。
  • MtypeQuery:查询对象,继承 Mtype 并添加分页参数,提供自动计算 startNum 的功能。

7. 数据库交互

  • 表结构假设包含字段 tidtname
  • 查询条件可根据 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 和公共片段提高代码复用性。

如需进一步优化,建议:

  1. 验证输入参数(如 pageNopageSize)的合法性,防止 SQL 注入。
  2. 使用 log 记录分页查询的关键数据,便于调试和性能优化。
Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐