MyBatis-Plus分页查询、分组查询

准备工作

1. 实体类

  • 对地址字段address使用字段类型转换器,将List转为字符串数组保存在数据库中
package com.example.server.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Data;

import java.util.List;

@Data
@TableName(autoResultMap = true)
public class SysUser {

    @TableId(type = IdType.AUTO)
    private String id;

    @TableLogic
    private Integer delFlag;

    private String name;

    private Integer age;

    private String gender;

    @TableField(typeHandler = JacksonTypeHandler.class)
    private List<String> address;

}

  • 对应的表
CREATE TABLE SYS_USER
(
    ID       INT PRIMARY KEY    NOT NULL AUTO_INCREMENT,
    NAME     VARCHAR(100)       NOT NULL,
    AGE      INT                NOT NULL,
    GENDER   VARCHAR(100)       NOT NULL,
    ADDRESS  VARCHAR(100)       NOT NULL,
    DEL_FLAG SMALLINT DEFAULT 0 NOT NULL
);

2. Mapper类

package com.example.server.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.server.entity.SysUser;

public interface SysUserMapper extends BaseMapper<SysUser> {


}

3. 分页插件

@Configuration
public class MybatisPlusConfig {

    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加
        // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
        return interceptor;
    }
}

4. 数据

在这里插入图片描述

分页查询

1. 使用条件构造器

  • 使用lambdaQuery条件构造器
package com.example.server;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.server.entity.SysUser;
import com.example.server.mapper.SysUserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class ServerApplicationTests {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Test
    void selectList() {
        IPage<SysUser> page = new Page<>(1, 10);
        // 只查询18和20岁的用户
        IPage<SysUser> userIPage = sysUserMapper.selectPage(page, Wrappers.<SysUser>lambdaQuery().in(SysUser::getAge, List.of(18, 20)).orderByAsc(SysUser::getId));
        System.out.println(JSON.toJSONString(userIPage));
    }

}

  • 打印结果
{
    "current": 1,
    "pages": 1,
    "records": [
        {
            "address": [
                "北京市朝阳区"
            ],
            "age": 20,
            "delFlag": 0,
            "gender": "MALE",
            "id": "1",
            "name": "Jack"
        },
        {
            "address": [
                "北京市朝阳区",
                "南京市鼓楼区"
            ],
            "age": 18,
            "delFlag": 0,
            "gender": "MALE",
            "id": "2",
            "name": "Fisher"
        }
    ],
    "size": 10,
    "total": 2
}

2. 使用自定义sql

  • 定义查询条件vo类
package com.example.server.vo;


import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class SysUserVO {

    private Integer ageMax;

    private Integer ageMin;

    private List<String> genderList;

    private List<String> addressList;

}

  • 动态sql,因为SysUser中使用了字段类型处理器typeHandler,需要手动指定resultMap(格式为”mybatis-plus_实体类”,和BaseMapper后的泛型类一致),否则address字段的转换器会不生效
package com.example.server.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.server.entity.SysUser;
import com.example.server.vo.SysUserVO;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.ResultMap;
import org.apache.ibatis.annotations.Select;


public interface SysUserMapper extends BaseMapper<SysUser> {

    @ResultMap("mybatis-plus_SysUser")
    @Select("<script>" +
            "SELECT * FROM SYS_USER WHERE DEL_FLAG = 0 " +
            "  <if test='sysUser.ageMax != null'>" +
            "AND AGE <![CDATA[ <= ]]> #{sysUser.ageMax} " +
            "  </if>" +
            "  <if test='sysUser.ageMin != null'>" +
            "AND AGE <![CDATA[ >= ]]> #{sysUser.ageMin} " +
            "  </if>" +
            " <if test='sysUser.genderList != null and sysUser.genderList.size() > 0'>" +
            "AND GENDER IN " +
            "<foreach collection='sysUser.genderList' item='item' open='(' separator=',' close=')'>" +
            "#{item}" +
            "</foreach>" +
            "  </if>" +
            " <if test='sysUser.addressList != null and sysUser.addressList.size() > 0'>" +
            "AND ( " +
            "<foreach collection='sysUser.addressList' item='item' index='index' open='' close='' separator='OR'>" +
            "ADDRESS LIKE concat('%', #{item}, '%') " +
            "</foreach>" +
            " )" +
            "  </if>" +
            "</script>")
    IPage<SysUser> selectUsersByPage(@Param("page") IPage<SysUser> page, @Param("sysUser") SysUserVO sysUser);

}

  • 测试方法
package com.example.server;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.server.entity.SysUser;
import com.example.server.mapper.SysUserMapper;
import com.example.server.vo.SysUserVO;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class ServerApplicationTests {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Test
    void selectUsersByPage() {
        // 分页查询,年龄在18到35岁之间,性别男或女,地址在北京或南京的用户
        IPage<SysUser> page = new Page<>(1, 10);
        SysUserVO sysUserVO = SysUserVO.builder().ageMax(35).ageMin(18).genderList(List.of("MALE", "FEMALE")).addressList(List.of("北京市", "南京市")).build();
        IPage<SysUser> userIPage = sysUserMapper.selectUsersByPage(page, sysUserVO);
        System.out.println(JSON.toJSONString(userIPage));
    }

}

  • 打印结果
{
    "current": 1,
    "pages": 1,
    "records": [
        {
            "address": [
                "北京市朝阳区"
            ],
            "age": 20,
            "delFlag": 0,
            "gender": "MALE",
            "id": "1",
            "name": "Jack"
        },
        {
            "address": [
                "北京市朝阳区",
                "南京市鼓楼区"
            ],
            "age": 18,
            "delFlag": 0,
            "gender": "MALE",
            "id": "2",
            "name": "Fisher"
        },
        {
            "address": [
                "北京市朝阳区"
            ],
            "age": 35,
            "delFlag": 0,
            "gender": "MALE",
            "id": "5",
            "name": "James"
        }
    ],
    "size": 10,
    "total": 3
}

分组查询

1. 分组结果类

  • 对性别进行分组统计
package com.example.server.dto;

import lombok.Data;

@Data
public class SysUserDTO {

    private String gender;

    private Integer num;

}

2. 自定义sql

package com.example.server.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.server.dto.SysUserDTO;
import com.example.server.entity.SysUser;
import org.apache.ibatis.annotations.Select;

import java.util.List;


public interface SysUserMapper extends BaseMapper<SysUser> {

    @Select("select gender, count(*) num from sys_user where del_flag = 0 GROUP BY gender")
    List<SysUserDTO> selectUsersByGender();

}

  • 这里没有使用mybatis-plus的groupBy方法进行统计,使用继承了BaseMapper<SysUser>后使用原生的api得到的返回值是SysUser,但是这里不好引入统计结果字段,如果加了,统计没有问题,但是查详情的时候有问题,因为表中没有这个字段

3. 测试类

package com.example.server;

import com.alibaba.fastjson.JSON;
import com.example.server.dto.SysUserDTO;
import com.example.server.mapper.SysUserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class ServerApplicationTests {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Test
    void selectUsersByGender() {
        // 对性别做分组统计
        List<SysUserDTO> sysUsers = sysUserMapper.selectUsersByGender();
        System.out.println(JSON.toJSONString(sysUsers));
    }

}

  • 打印结果
[
    {
        "gender": "MALE",
        "num": 4
    },
    {
        "gender": "FEMALE",
        "num": 1
    }
]
### 使用 MyBatisPlus 在三层架构中实现分组统计功能 #### 1. 数据库设计与准备 在三层架构中,数据库层的设计至关重要。假设我们有一个 `blog` 表记录博客文章的信息,其中包括作者 ID (`author_id`) 和阅读次数 (`read_count`) 字段。为了实现按作者分组并统计每篇文章总阅读量的功能,可以先定义 SQL 查询语句: ```sql SELECT author_id, SUM(read_count) AS total_read FROM blog GROUP BY author_id; ``` 此查询会返回每位作者的文章总阅读数。 #### 2. DAO 层 (Mapper 接口) MyBatis-Plus 提供了强大的 Mapper 功能来简化 CRUD 操作以及自定义 SQL 的支持。可以通过继承 BaseMapper 并扩展方法完成分组统计操作。 创建 BlogMapper 类作为接口文件: ```java @Mapper public interface BlogMapper extends BaseMapper<Blog> { List<Map<String, Object>> getAuthorTotalRead(); } ``` 接着,在对应的 XML 文件或者通过注解形式定义具体的方法体内容。如果采用 XML 方式,则需新增如下片段于 mapper.xml 中: ```xml <select id="getAuthorTotalRead" resultType="map"> SELECT author_id, SUM(read_count) as total_read FROM blog GROUP BY author_id </select> ``` 以上代码实现了基于作者维度的聚合计算[^1]。 #### 3. Service 层 Service 层负责处理业务逻辑和服务调用关系管理。通常情况下它封装了多个 Dao 方法组合而成复杂流程,并向 Controller 曝露统一入口。 构建服务类 BlogService 及其实现类 BlogServiceImpl 如下所示: ```java @Service public class BlogServiceImpl implements IBlogService { @Autowired private BlogMapper blogMapper; public Map<Integer, Integer> listAuthorTotalRead() { List<Map<String, Object>> resultList = blogMapper.getAuthorTotalRead(); HashMap<Integer,Integer> resultMap=new HashMap<>(); for(Map<String,Object> item:resultList){ int authorId=(int)item.get("author_id"); int totalRead=((BigDecimal)item.get("total_read")).intValue(); resultMap.put(authorId,totalRead); } return resultMap; } } ``` 这里我们将原始结果转换成更易读的形式——键值对结构,其中 key 是作者ID而 value 则代表对应用户的全部博文累计访问数量[^2]。 #### 4. Controller 层 最后一步是在控制器(Controller)级别暴露 RESTful API 给前端应用消费这些统计数据。下面展示了一个简单的例子说明如何设置路径映射及其关联的服务实例化过程: ```java @RestController @RequestMapping("/api/blog") public class BlogController { @Resource private IBlogService iBlogService; @GetMapping("/authors-total-reads") public ResponseEntity<?> fetchAuthorsTotalRead(){ try{ Map<Integer,Integer> data=iBlogService.listAuthorTotalRead(); return new ResponseEntity<>(data, HttpStatus.OK); }catch(Exception e){ log.error(e.getMessage(),e); return new ResponseEntity<>("Error occurred",HttpStatus.INTERNAL_SERVER_ERROR ); } } } ``` 至此完成了整个三层架构下的分组统计功能开发工作流描述[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fisher3652

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值