从零搭建若依(Ruoyi-Vue)管理系统(9)–Mybatias分页支持

项目地址:https://github.com/Gang-bb/Gangbb-Vue
本章结束后对应的节选代码文件:Gangbb-Vue-09-PageHelper

历史遗留TODO:

  • 第四章
  1. 登录日志还未实现。(到登录和权限模块完成)
  2. LogAspect从缓存获取当前的用户信息使用模拟的数据(到登录和权限模块完成)

本章将留下TODO:

本章将解决TODO:

本来这章应该跟Mybatis一起的,给落下了,现在补回来

1. 引入依赖

1.1 Gangbb-Vue的pom.xml

在第三章中已经在 Gangbb-Vue引入了分页的依赖。

1.2 Gangbb-common的pom.xml

<dependencies>
	<!-- pagehelper 分页插件  begin-->
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper-spring-boot-starter</artifactId>
    </dependency>
    <!-- pagehelper 分页插件  end-->
</dependencies>

2.配置yml

# PageHelper分页插件
pagehelper:
  # 指定分页插件使用哪种数据库方言
  helperDialect: mysql
  # 当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页。
  reasonable: true
  # 支持通过 Mapper 接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。
  supportMethodsArguments: true

这里简单配置了几项。

所有配置项:

  1. helperDialect:分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置helperDialect属性来指定分页插件使用哪种方言。配置时,可以使用下面的缩写值:
    oracle,mysql,mariadb,sqlite,hsqldb,postgresql,db2,sqlserver,informix,h2,sqlserver2012,derby
    **特别注意:**使用 SqlServer2012 数据库时,需要手动指定为 sqlserver2012,否则会使用 SqlServer2005 的方式进行分页。
    你也可以实现 AbstractHelperDialect,然后配置该属性为实现类的全限定名称即可使用自定义的实现方法。
  2. offsetAsPageNum:默认值为 false,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为 true 时,会将 RowBounds 中的 offset 参数当成 pageNum 使用,可以用页码和页面大小两个参数进行分页。
  3. rowBoundsWithCount:默认值为false,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为true时,使用 RowBounds 分页会进行 count 查询。
  4. pageSizeZero:默认值为 false,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0 就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是 Page 类型)。
  5. reasonable:分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。
  6. params:为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值, 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值, 默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero
  7. supportMethodsArguments:支持通过 Mapper 接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。 使用方法可以参考测试代码中的 com.github.pagehelper.test.basic 包下的 ArgumentsMapTestArgumentsObjTest
  8. autoRuntimeDialect:默认值为 false。设置为 true 时,允许在运行时根据多数据源自动识别对应方言的分页 (不支持自动选择sqlserver2012,只能使用sqlserver),用法和注意事项参考下面的场景五
  9. closeConn:默认值为 true。当使用运行时动态数据源或没有设置 helperDialect 属性自动获取数据库类型时,会自动获取一个数据库连接, 通过该属性来设置是否关闭获取的这个连接,默认true关闭,设置为 false 后,不会关闭获取的连接,这个参数的设置要根据自己选择的数据源来决定。
  10. aggregateFunctions(5.1.5+):默认为所有常见数据库的聚合函数,允许手动添加聚合函数(影响行数),所有以聚合函数开头的函数,在进行 count 转换时,会套一层。其他函数和列会被替换为 count(0),其中count列可以自己配置。

更多信息可以可以看官方文档:

https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md

3. 封装分页相关工具

3.1 BaseController

这是一个web层通用处理类。核心方法startPage()请求分页数据方法,使继承BaseController的Controller可以快速使用分页。

public class BaseController {
    protected final Logger logger = LoggerFactory.getLogger(BaseController.class);

    /**
     * 将前台传递过来的日期格式的字符串,自动转化为Date类型
     */
    @InitBinder
    public void initBinder(WebDataBinder binder)
    {
        // Date 类型转换
        binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
        {
            @Override
            public void setAsText(String text)
            {
                setValue(DateUtils.parseDate(text));
            }
        });
    }

    /**
     * 设置请求分页数据
     */
    protected void startPage()
    {
        //从前端获取分页参数
        MyPage pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();
        if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize))
        {
            String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
            PageHelper.startPage(pageNum, pageSize, orderBy);
        }
    }

    /**
     * 响应请求分页数据
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    protected TableDataInfo getDataTable(List<?> list)
    {
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        rspData.setRows(list);
        rspData.setTotal(new PageInfo(list).getTotal());
        return rspData;
    }

    /**
     * 响应返回结果
     *
     * @param rows 影响行数
     * @return 操作结果
     */
    protected ApiRestResponse toApiRes(int rows)
    {
        return rows > 0 ? ApiRestResponse.success() : ApiRestResponse.error();
    }

    /**
     * 页面跳转
     */
    public String redirect(String url)
    {
        return StringUtils.format("redirect:{}", url);
    }
}

3.2 TableDataInfo

若依封装的自定义分页结果。只有4个参数,感觉不太够。还是Pagehelper提供的PageInfo类返回的信息比较全。

对比一下便知:

若依TableDataInfo返回的信息:

{
    "total": 5,
    "rows": [
        {
            "creator": "",
            "createTime": "2021-03-10 15:04:32",
            "reviser": "",
            "updateTime": null,
            "isDel": 0,
            "remark": "",
            "id": 1160,
            "title": "测试系统自定义异常",
            "businessType": 0,
            "businessTypes": null,
            "classMethod": "com.gangbb.test.controller.TestExceptionController.testApiException()",
            "requestMethod": "GET",
            "operatorType": 1,
            "operationName": "Gangbb",
            "operationUrl": "/test/exception/e",
            "operationIp": "127.0.0.1",
            "operationLocation": "内网IP",
            "operationParam": "{}",
            "jsonResult": "null",
            "operationStatus": 1,
            "errorMsg": "System internal errors",
            "operationTime": "2021-03-10 15:04:32"
        },
        {
            "creator": "",
            "createTime": "2021-03-10 15:05:43",
            "reviser": "",
            "updateTime": null,
            "isDel": 0,
            "remark": "",
            "id": 1161,
            "title": "测试success",
            "businessType": 0,
            "businessTypes": null,
            "classMethod": "com.gangbb.test.controller.TestExceptionController.testSuccess()",
            "requestMethod": "POST",
            "operatorType": 1,
            "operationName": "Gangbb",
            "operationUrl": "/test/exception/success",
            "operationIp": "127.0.0.1",
            "operationLocation": "内网IP",
            "operationParam": "",
            "jsonResult": "{\"code\":\"20000\",\"msg\":\"操作成功(success)\",\"data\":{\"info\":\"Test\",\"name\":\"LLL\"}}",
            "operationStatus": 0,
            "errorMsg": null,
            "operationTime": "2021-03-10 15:05:43"
        }
    ],
    "code": 200,
    "msg": "查询成功"
}

TableDataInfo类代码自行看项目文件,不再贴出。

PageInfo返回的信息:

{
    "total": 5,
    "list": [
        {
            "creator": "",
            "createTime": "2021-03-10 15:04:32",
            "reviser": "",
            "updateTime": null,
            "isDel": 0,
            "remark": "",
            "id": 1160,
            "title": "测试系统自定义异常",
            "businessType": 0,
            "businessTypes": null,
            "classMethod": "com.gangbb.test.controller.TestExceptionController.testApiException()",
            "requestMethod": "GET",
            "operatorType": 1,
            "operationName": "Gangbb",
            "operationUrl": "/test/exception/e",
            "operationIp": "127.0.0.1",
            "operationLocation": "内网IP",
            "operationParam": "{}",
            "jsonResult": "null",
            "operationStatus": 1,
            "errorMsg": "System internal errors",
            "operationTime": "2021-03-10 15:04:32"
        },
        {
            "creator": "",
            "createTime": "2021-03-10 15:05:43",
            "reviser": "",
            "updateTime": null,
            "isDel": 0,
            "remark": "",
            "id": 1161,
            "title": "测试success",
            "businessType": 0,
            "businessTypes": null,
            "classMethod": "com.gangbb.test.controller.TestExceptionController.testSuccess()",
            "requestMethod": "POST",
            "operatorType": 1,
            "operationName": "Gangbb",
            "operationUrl": "/test/exception/success",
            "operationIp": "127.0.0.1",
            "operationLocation": "内网IP",
            "operationParam": "",
            "jsonResult": "{\"code\":\"20000\",\"msg\":\"操作成功(success)\",\"data\":{\"info\":\"Test\",\"name\":\"LLL\"}}",
            "operationStatus": 0,
            "errorMsg": null,
            "operationTime": "2021-03-10 15:05:43"
        }
    ],
    "pageNum": 1,
    "pageSize": 2,
    "size": 2,
    "startRow": 1,
    "endRow": 2,
    "pages": 3,
    "prePage": 0,
    "nextPage": 2,
    "isFirstPage": true,
    "isLastPage": false,
    "hasPreviousPage": false,
    "hasNextPage": true,
    "navigatePages": 8,
    "navigatepageNums": [
        1,
        2,
        3
    ],
    "navigateFirstPage": 1,
    "navigateLastPage": 3
}

3.3 数据传输类PageDto

若依源码中叫PageDomain

主要的属性:

/** 当前记录起始索引 */
private Integer pageNum;

/** 每页显示记录数 */
private Integer pageSize;

/** 排序列 */
private String orderByColumn;

/** 排序的方向desc或者asc */
private String isAsc = "asc";

这是前端调用接口时,可选择传入的参数。

而参数传递的声明,没有写在各个使用分页方法的参数列表中。直接通过TableSupport从客户端工具类ServletUtils中获取分页请求的各项可填参数。

但是若依如此设计,实测没有进行参数校验。例如:

image-20210312225628585

pageNum传入一个字母,这时返回的结果是全部数据也未分页,对于前端是不利于排查的。

使用时可以增加一些适当的校验。例如:

image-20210312233357712

(只是举例,实际应用应该更严谨一点)

校验:

image-20210312233318465

本章在全局错误处理GlobalExceptionHandler增加了对MethodArgumentTypeMismatchException参数转换异常的处理。

/**
 * MethodArgumentTypeMismatchException 参数类型转换异常
 */
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ApiRestResponse resolveMethodArgumentNotValidException(MethodArgumentTypeMismatchException ex){
    String msg = "参数<" + ex.getName() + ">校验失败:" +  ex.getMessage();
    return ApiRestResponse.error("A0003", msg);
}

3.4 一些工具类

DateUtils:时间工具类

TableSupport :获取分页参数

SqlUtil:sql操作工具类

(代码自行到项目中复制)


版权声明:本文为qq_37132495原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>