Spring3整合MyBatis实现分页查询和搜索

在实际项目开发中,数据库数据量往往较大,直接查询全量数据会导致性能下降、页面加载缓慢;同时,用户需要快速定位目标数据,搜索功能必不可少。本文基于 MyBatis 框架,结合前端 Vue+Element UI 与后端 SpringBoot 技术栈,详细讲解分页查询与搜索功能的完整实现流程,涵盖后端插件配置、动态 SQL 编写、前端请求封装与页面展示,帮助开发者高效落地核心业务功能。

一、技术栈说明与环境准备

1.1 核心技术栈

后端:SpringBoot(基础框架)、MyBatis(持久层框架)、PageHelper(MyBatis 分页插件)、MySQL(数据库)

前端:Vue3(前端框架)、axios(HTTP 请求工具)、Element UI(UI 组件库,含 el-table 表格、el-pagination 分页、el-input 搜索框等组件)

1.2 环境准备

后端:确保已完成 SpringBoot 与 MyBatis 的基础整合(可参考前文 SpringBoot3 整合 MyBatis 步骤),引入 PageHelper 依赖;

前端:搭建 Vue3+Element UI 项目,安装 axios 依赖,配置基础请求拦截器。

二、安装依赖

复制代码
npm i axios -S

三、简单测试axios

在Home.vue当中配置

复制代码
import axios from "axios";

axios.get("http://localhost:8080/user/findAll").then(res => {
  console.log(res.data);
});

四、SpringBoot设置跨域配置

前后端分离项目中,前端请求后端接口会存在跨域问题(浏览器同源策略限制),需在 SpringBoot 中添加跨域配置,允许前端域名的请求访问。

复制代码
package com.qcby.schoolshop.common;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter() {
        // 1. 创建CORS配置对象
        CorsConfiguration config = new CorsConfiguration();
        // 允许的源(前端地址,*表示允许所有源,生产环境建议指定具体地址)
        config.addAllowedOrigin("http://localhost:5173");
        // 允许的请求头(*表示允许所有)
        config.addAllowedHeader("*");
        // 允许的请求方法(*表示允许所有,也可以指定GET、POST、PUT等)
        config.addAllowedMethod("*");
        // 允许携带Cookie(如果需要跨域传递Cookie,需要开启这个,且前端请求也要配置withCredentials: true)
        config.setAllowCredentials(true);
        // 预检请求的缓存时间(单位:秒,减少预检请求的次数)
        config.setMaxAge(3600L);

        // 2. 配置路径映射(/**表示所有路径)
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);

        // 3. 返回CORS过滤器
        return new CorsFilter(source);
    }
}

原因:前后端分离项目中,前端和后端通常运行在不同域名 / 端口(如前端 8081、后端 8080),浏览器的 "同源策略" 会禁止这种跨源请求,设置跨域是为了允许前端合法访问后端接口,避免请求被拦截,确保数据正常交互。

重启测试

五、封装统一的请求工具:request.js

为了简化重复代码 (不用每次请求都写基础配置)、统一管理请求规则(如基础 URL、超时时间、请求头),还能集中处理请求 / 响应拦截(如 Token 添加、错误提示),提升代码复用性和可维护性,以后方便使用,我们新建一个request.js的文件来处理后台发来的数据

复制代码
 import axios from "axios";
 axios.get('http://localhost:8080/user/findAll').then(res=>{
     console.log(res)
 })
复制代码
import axios from "axios";
import {ElMessage} from "element-plus";

const request = axios.create({
  baseURL: 'http://localhost:9999',
  timeout: 30000  // 后台接口超时时间
})

// request 拦截器
// 可以自请求发送前对请求做一些处理
request.interceptors.request.use(config => {
  config.headers['Content-Type'] = 'application/json;charset=utf-8';
  return config
}, error => {
  return Promise.reject(error)
});

// response 拦截器
// 可以在接口响应后统一处理结果
request.interceptors.response.use(
  response => {
    let res = response.data;
    // 兼容服务端返回的字符串数据
    if (typeof res === 'string') {
      res = res ? JSON.parse(res) : res
    }
    return res;
  },
  error => {
    if (error.response.status === 404) {
      ElMessage.error('未找到请求接口')
    } else if (error.response.status === 500) {
      ElMessage.error('系统异常,请查看后端控制台报错')
    } else {
      console.error(error.message)
    }
    return Promise.reject(error)
  }
)
export default request

六、设置查询分页

6.1 Mapper.xml文件

复制代码
<!--注意最后别写;-->
<select id="findAll" resultType="com.qcby.vuespringbootdemo.entity.User">
    select * from user order by id desc 
</select>

6.2 导入分页的jar包 pom.xml

复制代码
<!-- 分页插件pagehelper -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.4.6</version>
    <!--排除和我们引入的mybatis的影响-->
    <exclusions>
        <exclusion>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
        </exclusion>
    </exclusions>
</dependency>

6.3 service层开启分页查询

复制代码
public PageInfo<User> selectPage(Integer pageNum,Integer pageSize){
    //开启分页查询
    PageHelper.startPage(pageNum,pageSize);
    List<User> users = userDao.findAll();
    return PageInfo.of(users);
}

6.4 Controller层

复制代码
@GetMapping("/selectPage")
@ResponseBody
public Result selectPage(@RequestParam(defaultValue = "1") Integer pageNum,
                         @RequestParam(defaultValue = "5")Integer pageSize){
    PageInfo<User> userPageInfo = userService.selectPage(pageNum, pageSize);
    return Result.success(userPageInfo);
}

6.5 接口测试

http://localhost:8081/user/selectPage?pageNum=1&pageSize=5

6.6 前端展示

复制代码
<div class="card" style="margin-bottom: 5px">
      <el-table :data="data.tableData" style="width: 100%" :header-cell-style="{ color: '#333', backgroundColor: '#eaf4ff' }">
        <!-- type="selection":这指定该列将包含用于行选择的复选框。它允许用户在表格中选择一行或多行。 -->
        <el-table-column type="selection" width="55" />
        <el-table-column prop="username" label="用户名" width="180" />
        <el-table-column prop="birthday" label="生日" width="180" />
        <el-table-column prop="sex" label="性别" width="80" />
        <el-table-column prop="address" label="地址" width="180" />
      </el-table>
    </div>

6.7 前端请求数据

复制代码
import { reactive } from "vue";
import {Search} from "@element-plus/icons-vue";
import request from "@/utils/request.js";
import {ElMessage} from "element-plus";

const data = reactive({
  name: null,
  pageNum: 1,
  pageSize: 5,
  total:0,
  tableData: []
})

const load = () => {
  request.get('/user/selectPage', {
    params: {
      pageNum: data.pageNum,
      pageSize: data.pageSize
    }
  }).then(res => {
    if (res.code === '200') {
      data.tableData = res.data.list
      data.total = res.data.total
    } else {
      ElMessage.error(res.msg)
    }
  })
}
load()

接下来处理一下时间的显示问题

复制代码
// 添加日期格式化函数
const dateFormat = (row, column, cellValue) => {
  if (!cellValue) return ''
  const date = new Date(cellValue)
  const year = date.getFullYear()
  const month = String(date.getMonth() + 1).padStart(2, '0')
  const day = String(date.getDate()).padStart(2, '0')
  return `${year}-${month}-${day}`
}

最后别忘了

复制代码
<div class="card">
      <el-pagination
          v-model:current-page="data.pageNum"
          :page-size="data.pageSize"
          layout="total, prev, pager, next"
          :total="data.total"
          @current-change="load"
          @size-change="load"
      />
    </div>

七、搜索设置

7.1 前端设置搜索框

复制代码
<div class="card" style="margin-bottom: 5px">
      <el-input clearable @clear="load" style="width: 260px; margin-right: 5px" v-model="data.username" placeholder="请输入用户名查询" :prefix-icon="Search"></el-input>
      <el-input clearable @clear="load" style="width: 260px; margin-right: 5px" v-model="data.address" placeholder="请输入地址查询" :prefix-icon="Search"></el-input>
      <el-button type="primary" @click="load">查 询</el-button>
      <el-button @click="reset">重 置</el-button>
</div>

7.2 前端设置入参

复制代码
 params: {
      pageNum: data.pageNum,
      pageSize: data.pageSize,
      username: data.username,
      address: data.address
    }

7.3 设置重置

复制代码
//搜索重置
const reset = () => {
  data.username = null
  data.address = null
  load()
}

7.4 Mapper.xml设置查询

复制代码
<select id="findAll" resultType="com.qcby.springboot.entity.User"
        parameterType="com.qcby.springboot.entity.User">
    select * from user
        <where>
           <if test="username!=null">
               username like concat('%', #{username}, '%')
           </if>
            <if test="address!=null">
                and address  like concat('%', #{address}, '%')
            </if>
        </where>
    order by id
</select>

7.5 service层

复制代码
@Override
public PageInfo<User> selectPage(Integer pageNum, Integer pageSize,User user) {
    //开启分页查询
    PageHelper.startPage(pageNum,pageSize);
    List<User> users = userDao.findAll(user);
    return PageInfo.of(users);
}

7.6 controller层

复制代码
@GetMapping("/selectPage")
@ResponseBody
public Result selectPage(@RequestParam(defaultValue = "1") Integer pageNum,
                         @RequestParam(defaultValue = "5")Integer pageSize,
                         User user){
    System.out.println(user.toString());
    PageInfo<User> userPageInfo = userService.selectPage(pageNum, pageSize,user);
    return Result.success(userPageInfo);
}
相关推荐
色空大师18 小时前
mybatis动态sql
sql·mybatis·foreach·where·sql动态语法
BD_Marathon21 小时前
自定义映射resultMap——通过collection解决一对多的映射关系(九)
mybatis
码农幻想梦21 小时前
实验四 mybatis动态sql及逆向工程
sql·性能优化·mybatis
小北方城市网1 天前
SpringBoot 集成 MyBatis-Plus 实战(高效 CRUD 与复杂查询):简化数据库操作
java·数据库·人工智能·spring boot·后端·安全·mybatis
码农幻想梦1 天前
实验三 Mybatis多表查询操作
mybatis
cab51 天前
MyBatis如何处理数据库中的JSON字段
数据库·json·mybatis
小北方城市网1 天前
SpringBoot 安全认证实战(Spring Security + JWT):打造无状态安全接口体系
数据库·spring boot·后端·安全·spring·mybatis·restful
Z_W_H_1 天前
MyBatis-Plus 详细学习文档
学习·mybatis
程序员侠客行1 天前
Mybatis插件原理及分页插件
java·后端·架构·mybatis