Mybatis-plus如何通过反射实现动态排序不同字段功能

 更新时间:2024年02月19日 14:19:30   作者:daizuojian  
这篇文章主要介绍了Mybatis-plus如何通过反射实现动态排序不同字段功能,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

Mybatis-plus反射实现动态排序不同字段

最近在做项目,使用到了Mybatis-plus,页面上需要对某些字段进行排序,原来是固定好哪些字段需要排序,然后在Controller里接收参数。

如下代码所示

	@LogOperation(name = "query urpOfi", objType = "Config")
    @GetMapping
    public ResponseEntity<DtoResponse<OfiDto>> queryOfi(
            @RequestParam(name = "pageSize", defaultValue = "-1", required = false) Integer pageSize,
            @RequestParam(name = "page", defaultValue = "-1", required = false) Integer page,
            @RequestParam(value = "sort", defaultValue = "", required = false) String sort,
            @RequestParam(value = "msFlag", defaultValue = "", required = false) String msFlag)
            throws UnsupportedEncodingException {
        sort = URLDecoder.decode(sort, StandardCharsets.UTF_8.toString());
        msFlag = URLDecoder.decode(msFlag, StandardCharsets.UTF_8.toString());
        余下省略......

其中@LogOperation使我们自定义的AOP日志注解,可以不用关注。

这里存在的问题是参数没有校验

直接接收了,可能会被恶意攻击,同时sort为排序字段,前台会传一个固定好的字段值过来,

无法实现动态排序(比如:前台随意传一个字段,只要在我的表数据Entity中存在该字段,就可以实现排序)

通过以下方式实现动态排序

@Data
public class BaseQueryDto<T> {
    // 排序方式标识符号,”-“代表倒序
    private static final String ORDER_BY_IDENTIFIER = "-";

    private static final int MAX_PAGE_SIZE = 100;

    private static final int MAX_PAGE = 10000;

    private static final int MAX_SORT_LENGTH = 100;

    /**
     * 每页显示记录数
     */
    @Range(min = 0, max = MAX_PAGE_SIZE)
    protected Integer pageSize = 10;

    /**
     * 当前页
     */
    @Range(min = 0, max = MAX_PAGE)
    protected Integer page = 0;

    /**
     * 排序,包含2部分内容,排序方式及排序字段
     */
    @Length(max = MAX_SORT_LENGTH)
    protected String sort;

    /**
     * 获取排序方式,默认升序(asc)
     *
     * @return 排序方式
     */
    public SqlOrderType getOrderType() {
        if (StringUtils.isEmpty(sort)) {
            return SqlOrderType.ASC;
        }

        if (sort.startsWith(ORDER_BY_IDENTIFIER)) {
            return SqlOrderType.DESC;
        }

        return SqlOrderType.ASC;
    }

    private Optional<Class<?>> getEntityClass() {
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
            try {
                return Optional.of(Class.forName(actualTypeArguments[0].getTypeName()));
            } catch (ClassNotFoundException e) {
                return Optional.empty();
            }
        }

        return Optional.empty();
    }

    private Optional<Field> getEntityField(String fieldName) {
        Optional<Class<?>> optionalClass = getEntityClass();

        return optionalClass.flatMap(it -> {
            try {
                return Optional.of(it.getDeclaredField(fieldName));
            } catch (NoSuchFieldException e) {
                return Optional.empty();
            }
        });
    }

    /**
     * 获取数据排序的列
     *
     * @return 排序列
     */
    public Optional<String> getOrderColumn() {
        if (StringUtils.isEmpty(sort)) {
            return Optional.empty();
        }
        return getEntityField(sort.replaceFirst(ORDER_BY_IDENTIFIER, "")).map(Field::getName);
    }

    /**
     * 设置排序的QueryWrapper
     *
     * @param queryWrapper query wrapper
     */
    public void setOrderQueryWrapper(QueryWrapper<T> queryWrapper) {
        this.getOrderColumn().ifPresent(column -> {
            queryWrapper.orderBy(true, this.getOrderType().equals(SqlOrderType.ASC), column);
        });
    }
}

BaseQueryDto是公共的查询Dto父类,泛型T为具体的表数据Entity。

通过java beanvalidation控制入参大小及长度,前端传递的参数sort值一般为Entity中的字段名,例如“id”或者“-id”,带有“-”的代表是降序。

会根据传入的sort值通过反射去判断在Entity中是否存在该字段,存在就正常排序,不存在就什么也不做。

如果只需要排序,那么Controller中用BaseQueryDto去接收参数即可,然后在Service中调用baseQueryDto.setOrderQueryWrapper(queryWrapper);

如果不仅仅排序,还需要对某些字段做模糊查询或者下拉框过滤查询,需要新建Dto继承BaseQueryDto。

@Data
public class OfiQueryDto extends BaseQueryDto<OfiEntity> {
    /**
     * 主从标识(过滤查询)
     */
    @Length(max = 5)
    private String msFlag = "";

    /**
     * 国内,国内备用,国际,国际备用网编码(模糊查询)
     */
    @Length(max = 6)
    private String networkCode1 = "";

    @Length(max = 6)
    private String networkCode2 = "";

    @Length(max = 6)
    private String networkCode3 = "";

    @Length(max = 6)
    private String networkCode4 = "";
}

Service中设置模糊查询,下拉框过滤和排序。

public ListPage<OfiEntity> queryOfiListPage(OfiQueryDto dto, Integer clusterId)
            throws UnsupportedEncodingException {
        QueryWrapper<OfiEntity> queryWrapper = Wrappers.query();
        queryWrapper.lambda().eq(OfiEntity::getClusterId, clusterId);

        setSelectQueryWrapper(dto, queryWrapper.lambda());

        setLikeQueryWrapper(dto, queryWrapper.lambda());

        dto.setOrderQueryWrapper(queryWrapper);

        Page<OfiEntity> ofiEntityPage = new Page<>(dto.getPage(), dto.getPageSize());
        ofiEntityPage = getBaseMapper().selectPage(ofiEntityPage, queryWrapper);

        return ListPage.of(ofiEntityPage);
    }

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • MyBatis之自查询使用递归实现 N级联动效果(两种实现方式)

    MyBatis之自查询使用递归实现 N级联动效果(两种实现方式)

    这篇文章主要介绍了MyBatis之自查询使用递归实现 N级联动效果,本文给大家分享两种实现方式,需要的的朋友参考下吧
    2017-07-07
  • 深入学习MyBatis中的参数(推荐)

    深入学习MyBatis中的参数(推荐)

    大家日常使用MyBatis经常会遇到一些异常,想要避免参数引起的错误,我们需要深入了解参数。想了解参数,我们首先看MyBatis处理参数和使用参数的全部过程。下面这篇文章主要给大家介绍了MyBatis中参数的的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-06-06
  • Spring实现处理跨域请求代码详解

    Spring实现处理跨域请求代码详解

    这篇文章主要介绍了Spring实现处理跨域请求代码详解,具有一定借鉴价值,需要的朋友可以了解下。
    2017-12-12
  • java实现鲜花销售系统

    java实现鲜花销售系统

    这篇文章主要为大家详细介绍了java实现鲜花销售系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • jdbc中class.forname的作用

    jdbc中class.forname的作用

    这篇文章主要介绍了jdbc中class.forname的作用,使用示例说明了他作用及使用方法,大家参考使用吧
    2014-01-01
  • springboot3环境隔离的实现

    springboot3环境隔离的实现

    在开发中,环境很多,本文主要介绍了springboot3环境隔离的实现,能够快速切换开发、测试、生产环境,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • 详解SpringMVC的拦截器链实现及拦截器链配置

    详解SpringMVC的拦截器链实现及拦截器链配置

    拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行。本文将详细讲讲SpringMVC中拦截器参数及拦截器链配置,感兴趣的可以尝试一下
    2022-08-08
  • Java缓存Map设置过期时间实现解析

    Java缓存Map设置过期时间实现解析

    这篇文章主要介绍了Java缓存Map设置过期时间实现解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • SpringBoot中SM2公钥加密、私钥解密的实现示例详解

    SpringBoot中SM2公钥加密、私钥解密的实现示例详解

    本文介绍了如何在SpringBoot项目中实现SM2公钥加密和私钥解密的功能,通过使用Hutool库和BouncyCastle依赖,简化了SM2加密的实现过程,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧
    2025-07-07
  • 用java实现杨辉三角的示例代码

    用java实现杨辉三角的示例代码

    本篇文章主要介绍了用java实现杨辉三角的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01

最新评论