SpringBoot | 基于 MyBatis 的分页与模糊查询的开发模板

news2025/1/8 14:24:45

关注:CodingTechWork

引言

  在开发 Web 应用时,常常需要处理复杂的查询需求,尤其是在涉及到用户管理功能时,分页查询和模糊查询是常见的需求之一。
  本文将通过一个具体的示例,展示如何使用 MyBatis实现分页和模糊查询,特别是如何使用CASE...WHEN...THEN语句进行用户名的模糊查询,并且支持其他精确查询条件。

需求背景

  我们需要实现一个分页查询功能,查询系统中的用户信息。每个用户包括用户名、用户组、邮箱、状态、注册时间等字段。此外,查询功能支持以下条件:

  1. 用户名模糊查询(其中精准匹配排序优先,左右匹配也有优先级)
  2. 用户组、状态的精确查询
  3. 注册时间范围查询
  4. 支持分页
  5. 时间排序
    最终,我们的目标是使用MyBatis提供的动态 SQL 功能,构建灵活的查询条件,并实现分页查询的功能。

实践模板

数据库设计

假设我们有一个 demo_user 表,存储了用户信息。表结构大致如下:

CREATE TABLE demo_user (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255) NOT NULL,
    user_group VARCHAR(255),
    email VARCHAR(255),
    status INT,
    registration_time DATETIME,
    is_deleted INT DEFAULT 0
);

MyBatis 配置Mapper XML 配置

  在 MyBatis 中,我们需要通过 XML 映射文件来定义 SQL 查询语句。我们将编写一个分页查询的 SQL,其中包含模糊查询和精确查询的条件。

<?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="com.selfcode.demo.mapper.UserMapper">

    <!-- 公共SQL,用于查询用户信息 -->
    <sql id="list_user">
        SELECT du.id,
               du.username,
               du.user_group,
               du.email,
               du.status,
               du.registration_time
        FROM demo_user du
    </sql>

    <!-- 分页查询用户信息 -->
    <select id="pageListUser" resultType="com.selfcode.demo.vo.UserVO">
        <include refid="list_user"></include>
        <where>
            <!-- 用户名模糊查询 -->
            <if test="dto.usernameFuzzyQuery != null and dto.usernameFuzzyQuery != ''">
                AND du.username LIKE CONCAT('%', #{dto.usernameFuzzyQuery}, '%')
            </if>
            <!-- 用户组精确查询 -->
            <if test="dto.userGroup != null and dto.userGroup != ''">
                AND du.user_group = #{dto.userGroup}
            </if>
            <!-- 用户状态精确查询 -->
            <if test="dto.status != null">
                AND du.status = #{dto.status}
            </if>
            <!-- 注册时间范围查询 -->
            <if test="dto.beginTime != null and dto.endTime != null">
                AND du.registration_time BETWEEN #{dto.beginTime} AND #{dto.endTime}
            </if>
            <!-- 未删除的用户 -->
            AND du.is_deleted = 0
        </where>
        <!-- 默认按照用户状态(开启)和注册时间倒序排列 -->
        ORDER BY du.status DESC, du.registration_time DESC
        <!-- 用户名模糊查询的优先级排序 -->
        <if test="dto.usernameFuzzyQuery != null and dto.usernameFuzzyQuery != ''">
            , CASE
            WHEN du.username = #{dto.usernameFuzzyQuery} THEN 1
            WHEN du.username LIKE CONCAT(#{dto.usernameFuzzyQuery}, '%') THEN 2
            WHEN du.username LIKE CONCAT('%', #{dto.usernameFuzzyQuery}) THEN 3
            ELSE 4
            END ASC
        </if>
    </select>

</mapper>

Mapper 接口

  接下来,我们需要定义一个 Java 接口来与Mapper XML配置文件进行映射。我们在接口中声明 pageListUser 方法来执行分页查询。

package com.selfcode.demo.mapper;

import com.selfcode.demo.dto.UserDTO;
import com.selfcode.demo.vo.UserVO;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface UserMapper {

    /**
     * 分页查询用户信息
     *
     * @param dto 查询条件
     * @return 用户信息列表
     */
    List<UserVO> pageListUser(@Param("dto") UserDTO dto);
}

查询条件 DTO

  在 Java 中,我们定义一个 UserDTO 类来封装查询条件,包括分页参数、用户名模糊查询、用户组、状态和注册时间范围等。

package com.selfcode.demo.dto;

import java.util.Date;

public class UserDTO {
    private String usernameFuzzyQuery;  // 模糊查询的用户名
    private String userGroup;           // 精确查询用户组
    private Integer status;             // 精确查询用户状态
    private Date beginTime;             // 查询起始时间
    private Date endTime;               // 查询结束时间
    private Integer pageNo = 1;         // 页码,默认从1开始
    private Integer pageSize = 10;      // 每页显示的记录数,默认每页10条

    // Getters 和 Setters
}

返回值 VO

  UserVO类用于存储查询返回的用户信息数据。它包括用户的 ID、用户名、用户组、邮箱、状态和注册时间等信息。

package com.selfcode.demo.vo;

import java.util.Date;

public class UserVO {
    private Long id;                    // 用户ID
    private String username;            // 用户名
    private String userGroup;           // 用户组
    private String email;               // 邮箱
    private Integer status;             // 用户状态(例如:启用、禁用)
    private Date registrationTime;      // 注册时间

    // Getters 和 Setters
}

服务层

  在服务层,我们定义 UserService 类来调用 Mapper 进行数据库查询。UserService 负责接收前端的请求,处理查询逻辑并返回结果。

package com.selfcode.demo.service;

import com.selfcode.demo.dto.UserDTO;
import com.selfcode.demo.mapper.UserMapper;
import com.selfcode.demo.vo.UserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    /**
     * 获取用户分页列表
     *
     * @param dto 查询条件
     * @return 用户列表
     */
    public List<UserVO> getUserList(UserDTO dto) {
        return userMapper.pageListUser(dto);
    }
}

控制器层

  最后,在控制器层,我们接收来自前端的请求,调用UserService方法来获取分页查询的结果,并返回给客户端。

package com.selfcode.demo.controller;

import com.selfcode.demo.dto.UserDTO;
import com.selfcode.demo.service.UserService;
import com.selfcode.demo.vo.UserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/api/user")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 获取分页查询用户列表
     *
     * @param username 模糊查询的用户名
     * @param userGroup 用户组
     * @param pageNo 当前页
     * @param pageSize 每页显示条数
     * @return 用户列表
     */
    @GetMapping("/list")
    public List<UserVO> listUsers(@RequestParam(defaultValue = "") String username,
                                   @RequestParam(defaultValue = "") String userGroup,
                                   @RequestParam(defaultValue = "1") Integer pageNo,
                                   @RequestParam(defaultValue = "10") Integer pageSize) {
        UserDTO dto = new UserDTO();
        dto.setUsernameFuzzyQuery(username);
        dto.setUserGroup(userGroup);
        dto.setPageNo(pageNo);
        dto.setPageSize(pageSize);

        return userService.getUserList(dto);
    }
}

MyBatis Mapper XML 配置详细解析

  在上述示例中,XML 配置文件主要用于定义 SQL 查询语句,并通过 MyBatis 的映射机制将 SQL 与 Java 方法进行绑定。接下来,我们将详细解析 Mapper XML 文件中的各个部分,包括 SQL 语句、动态 SQL 标签、条件判断、排序等内容。

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="com.selfcode.demo.mapper.UserMapper">
  1. <?xml version="1.0" encoding="UTF-8"?>:声明这是一个 XML 文件,并且使用 UTF-8 编码。
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">:引入 MyBatis 3.0 的 DTD 定义文件,这个声明确保 XML 文件遵循 MyBatis 的规范。
  3. <mapper namespace="com.selfcode.demo.mapper.UserMapper">:定义了 Mapper 的命名空间,与 Java 中的 UserMapper接口类进行关联。MyBatis 会根据这个 namespace来找到对应的 SQL 配置,进行映射。

定义公共 SQL 语句 ()

<sql id="list_user">
    SELECT du.id,
           du.username,
           du.user_group,
           du.email,
           du.status,
           du.registration_time
    FROM demo_user du
</sql>
  1. <sql>:用于定义一个公共的 SQL 片段。通过id="list_user"来给这个 SQL 片段命名,其他地方可以通过 <include> 标签来引用它。
  2. SELECT:这是查询 demo_user 表的 SQL 语句,选择了用户的 id、username、user_group、email、status 和 registration_time 等字段。

分页查询的 SQL

(<select id="pageListUser" resultType="com.selfcode.demo.vo.UserVO">)

<select id="pageListUser" resultType="com.selfcode.demo.vo.UserVO">
    <include refid="list_user"></include>
    <where>
        <!-- 条件部分 -->
    </where>
    <order by>
        <!-- 排序部分 -->
    </order by>
</select>
  1. <select>:定义一个 SELECT 查询的 SQL 语句。id="pageListUser" 表示该 SQL 语句映射到 UserMapper 接口中的 pageListUser 方法。
  2. resultType="com.selfcode.demo.vo.UserVO":指定该查询返回的数据类型为UserVO(一个 VO 对象,用于存储返回的用户信息)。

引用公共 SQL

<include refid="list_user"></include>
  1. <include refid="list_user">:通过 <include> 标签引用上面定义的公共 SQL 片段。这样可以避免重复编写相同的查询字段,提升代码的复用性。

动态条件查询

<where>

<where>
    <!-- 用户名模糊查询 -->
    <if test="dto.usernameFuzzyQuery != null and dto.usernameFuzzyQuery != ''">
        AND du.username LIKE CONCAT('%', #{dto.usernameFuzzyQuery}, '%')
    </if>
    <!-- 用户组精确查询 -->
    <if test="dto.userGroup != null and dto.userGroup != ''">
        AND du.user_group = #{dto.userGroup}
    </if>
    <!-- 用户状态精确查询 -->
    <if test="dto.status != null">
        AND du.status = #{dto.status}
    </if>
    <!-- 注册时间范围查询 -->
    <if test="dto.beginTime != null and dto.endTime != null">
        AND du.registration_time BETWEEN #{dto.beginTime} AND #{dto.endTime}
    </if>
    <!-- 未删除的用户 -->
    AND du.is_deleted = 0
</where>
  1. <where><where> 标签用于处理 SQL 中的 WHERE 子句。MyBatis 会自动处理在动态 SQL 中添加 AND 或 OR 的位置,避免出现多余的 AND(例如,如果没有任何条件时,WHERE 会自动去掉)。
  2. <if test="...">:动态 SQL 条件判断。如果 test 表达式的条件成立,才会执行对应的 SQL 片段。比如,只有当 dto.usernameFuzzyQuery 不为空时,才会添加用户名的模糊查询条件。

用户名模糊查询:

<if test="dto.usernameFuzzyQuery != null and dto.usernameFuzzyQuery != ''">
    AND du.username LIKE CONCAT('%', #{dto.usernameFuzzyQuery}, '%')
</if>
  • 如果 dto.usernameFuzzyQuery 不为空,则生成 AND du.username LIKE '%...%' 条件进行模糊匹配。

用户组精确查询:

<if test="dto.userGroup != null and dto.userGroup != ''">
    AND du.user_group = #{dto.userGroup}
</if>
  • 如果 dto.userGroup 不为空,则会生成 AND du.user_group = '...' 条件。

用户状态精确查询:

<if test="dto.status != null">
    AND du.status = #{dto.status}
</if>
  • 如果dto.status 不为 null,则添加AND du.status = ...条件进行精确查询。

注册时间范围查询:

<if test="dto.beginTime != null and dto.endTime != null">
    AND du.registration_time BETWEEN #{dto.beginTime} AND #{dto.endTime}
</if>
  • 如果dto.beginTimedto.endTime 都不为空,则生成一个时间范围查询 BETWEEN 子句。

软删除条件:

AND du.is_deleted = 0
  • 这是一个硬编码的条件,用来过滤掉已删除的用户,假设 is_deleted = 1 表示用户已删除。

排序

<order by>

ORDER BY du.status DESC, du.registration_time DESC
<if test="dto.usernameFuzzyQuery != null and dto.usernameFuzzyQuery != ''">
    , CASE
    WHEN du.username = #{dto.usernameFuzzyQuery} THEN 1
    WHEN du.username LIKE CONCAT(#{dto.usernameFuzzyQuery}, '%') THEN 2
    WHEN du.username LIKE CONCAT('%', #{dto.usernameFuzzyQuery}) THEN 3
    ELSE 4
    END ASC
</if>
  1. ORDER BY:默认按 status字段降序排列,如果status相同,再按 registration_time 降序排列。
  2. CASE语句:如果用户提供了usernameFuzzyQuery 进行模糊查询,我们根据匹配程度来排序。具体逻辑如下:
    • 如果用户名完全匹配 dto.usernameFuzzyQuery,则给这个记录排序为优先(1)。
    • 如果用户名是以 dto.usernameFuzzyQuery 开头匹配,排序为第二(2)。
    • 如果用户名是以 dto.usernameFuzzyQuery 结尾匹配,排序为第三(3)。
    • 其他情况,排序为最后(4)。
      通过这种方式,我们将更精确的匹配记录排在前面,提升用户体验。

总结

  本文展示了如何使用 MyBatis 实现一个分页和模糊查询的用户列表查询功能。通过灵活的动态 SQL 配置,我们可以根据用户的输入条件动态生成查询语句,从而实现高效的数据库查询。
  这个 XML 配置通过 MyBatis 动态 SQL 功能,结合 标签、 标签和 CASE 语句,实现了以下功能:

  1. 分页查询:可以根据传入的条件动态生成 WHERE 子句,支持多种查询条件(模糊查询、精确查询、时间范围查询)。
  2. 动态条件:根据用户输入的条件,动态构建 SQL 查询,避免了不必要的条件拼接。
  3. 排序优化:通过 CASE 语句实现了对模糊查询结果的排序优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2273257.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

wujie无界微前端框架初使用

先说一下项目需求&#xff1a;将单独的四套系统的登录操作统一放在一个入口页面进行登录&#xff0c;所有系统都使用的是vue3&#xff0c;&#xff08;不要问我为啥会这样设计&#xff0c;产品说的客户要求&#xff09; 1.主系统下载wujie 我全套都是vue3&#xff0c;所以直接…

SpringIOC循环依赖与三级缓存

SpringIOC循环依赖与三级缓存 Spring解决循环依赖的核心机制就是通过三级缓存&#xff1a; 一级缓存&#xff08;singletonObjects&#xff09;&#xff1a;存储完全初始化好的Bean&#xff1b;二级缓存&#xff08;earlySingletonObjects&#xff09;&#xff1a;存储原始实例…

【顶刊TPAMI 2025】多头编码(MHE)之极限分类 Part 3:算法实现

目录 1 三种多头编码&#xff08;MHE&#xff09;实现1.1 多头乘积&#xff08;MHP&#xff09;1.2 多头级联&#xff08;MHC&#xff09;1.3 多头采样&#xff08;MHS&#xff09;1.4 标签分解策略 论文&#xff1a;Multi-Head Encoding for Extreme Label Classification 作者…

前端 图片上鼠标画矩形框,标注文字,任意删除

效果&#xff1a; 页面描述&#xff1a; 对给定的几张图片&#xff0c;每张能用鼠标在图上画框&#xff0c;标注相关文字&#xff0c;框的颜色和文字内容能自定义改变&#xff0c;能删除任意画过的框。 实现思路&#xff1a; 1、对给定的这几张图片&#xff0c;用分页器绑定…

【办公利器】ReNamer (批量文件重命名工具) Pro v7.6.0.4 多语便携版,海量文件秒速精准改名!

ReNamer是一款功能强大的文件重命名工具&#xff0c;它可以帮助用户快速方便地批量重命名文件和文件夹。 软件功能 批量重命名&#xff1a;ReNamer可以同时处理多个文件和文件夹&#xff0c;并对其进行批量重命名&#xff0c;从而节省时间和劳动力。灵活的重命名规则&#xff…

unity学习13:gameobject的组件component以及tag, layer 归类

目录 1 gameobject component 是unity的基础 1.1 类比 1.2 为什么要这么设计&#xff1f; 2 从空物体开始 2.1 创建2个物体 2.2 给 empty gameobject添加组件 3 各种组件和新建组件 3.1 点击 add component可以添加各种组件 3.2 新建组件 3.3 组件的操作 3.4 特别的…

数据库模型全解析:从文档存储到搜索引擎

目录 前言1. 文档存储&#xff08;Document Store&#xff09;1.1 概念与特点1.2 典型应用1.3 代表性数据库 2. 图数据库&#xff08;Graph DBMS&#xff09;2.1 概念与特点2.2 典型应用2.3 代表性数据库 3. 原生 XML 数据库&#xff08;Native XML DBMS&#xff09;3.1 概念与…

CSS——1.优缺点

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title><link rel"stylesheet" type"text/css" href"1-02.css"/></head><body><!--css&#xff1a;层叠样式表…

UE5本地化和国际化语言

翻译语言 工具 - 本地化控制板 Localization Dashboard 修改图中这几个地方就可以 点击箭头处&#xff0c;把中文翻译成英语&#xff0c;如果要更多语言就点 添加新语言 最后点击编译即可 编译完&#xff0c;会在目录生成文件夹 设置界面相关蓝图中设置 切换本地化语言 必须在…

python学习笔记—15—数据容器之列表

1. 数据容器 列表(list)、元组(tuple)、字符串(str)、集合(set)、字典(dict) 2. 列表 (1) 定义 tmp_list ["super", "carry", "doinb"] print(f"tmp_list {tmp_list}, tmp_list type is {type(tmp_list)}") tmp_list1 ["doi…

【简博士统计学习方法】第1章:4. 模型的评估与选择

4. 模型的评估与选择 4.1 训练误差与测试误差 假如存在样本容量为 N N N的训练集&#xff0c;将训练集送入学习系统可以训练学习得到一个模型&#xff0c;我们将这么模型用决策函数的形式表达&#xff0c;也就是 y f ^ ( x ) y\hat{f}(x) yf^​(x)&#xff0c;关于模型的拟合…

Unity自定义编辑器:基于枚举类型动态显示属性

1.参考链接 2.应用 target并设置多选编辑 添加[CanEditMultipleObjects] using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor;[CustomEditor(typeof(LightsState))] [CanEditMultipleObjects] public class TestInspector :…

cesium小知识:3D tiles 概述、特点、示例

Cesium 的 3D Tiles 是一种高效的、流式传输的三维地理空间数据格式,专为在Web浏览器中快速渲染大规模三维场景而设计。3D Tiles 支持多种几何类型,包括点云、多边形、模型等,并且可以包含丰富的属性信息和层次细节(LOD, Level of Detail)结构,以确保不同设备和网络条件下…

【微服务】7、分布式事务

在分布系统中&#xff0c;一个业务由多个服务合作完成&#xff0c;每个服务有自己的事务&#xff0c;多个事务需同时成功或失败&#xff0c;这样的事务称为分布式事务。 其中每个服务的事务叫分支事务&#xff0c;整个业务的统一事务叫全局事务。 分布式事务相关知识讲解 课程引…

基于 Boost.Asio 和 Boost.Beast 的异步 HTTP 服务器(学习记录)

已完成功能&#xff1a; 支持 GET 和 POST 请求的路由与回调处理。 解析URL请求。 单例模式 管理核心业务逻辑。 异步 I/O 技术和 定时器 控制超时。 通过回调函数注册机制&#xff0c;可以灵活地为不同的 URL 路由注册处理函数。 1. 项目背景 1.1 项目简介 本项目是一个基于…

Linux标准IOday1

1:思维导图 2:将 student.c这个练习题&#xff0c;改成链表后实现 头文件link.h #ifndef __STRUCT_H__ #define __STRUCT_H__ #include <stdio.h> #include <stdlib.h> typedef struct Student{char name[20];double math;double chinese;double english;double…

全局变量(PHP)(小迪网络安全笔记~

免责声明&#xff1a;本文章仅用于交流学习&#xff0c;因文章内容而产生的任何违法&未授权行为&#xff0c;与文章作者无关&#xff01;&#xff01;&#xff01; 附&#xff1a;完整笔记目录~ ps&#xff1a;本人小白&#xff0c;笔记均在个人理解基础上整理&#xff0c;…

gateway的路径匹配介绍

gateway是一个单独服务。通过网关端口和predicates进行匹配服务 1先看配置。看我注解你就明白了。其实就是/order/**配置机制直接匹配到orderservice服务。 2我试着请求一个路径&#xff0c;请求成功。下面第三步是请求的接口。 3接口。

RabbitMQ-基本使用

RabbitMQ: One broker to queue them all | RabbitMQ 官方 安装到Docker中 docker run \-e RABBITMQ_DEFAULT_USERrabbit \-e RABBITMQ_DEFAULT_PASSrabbit \-v mq-plugins:/plugins \--name mq \--hostname mq \-p 15672:15672 \-p 5672:5672 \--network mynet\-d \rabbitmq:3…

模式识别-Ch2-分类错误率

分类错误率 最小错误率贝叶斯决策 样本 x x x的错误率&#xff1a; 任一决策都可能会有错误。 P ( error ∣ x ) { P ( w 2 ∣ x ) , if we decide x as w 1 P ( w 1 ∣ x ) , if we decide x as w 2 P(\text{error}|\mathbf{x})\begin{cases} P(w_2|\mathbf{x}), &…