Java自定义字段动态排序

一、需求

现有一个业务,需要根据表头字段对返回的数据进行升序、降序排序,目前只支持数字类型,如图:
在这里插入图片描述

二、pom依赖


        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.1.4</version>
        </dependency>


        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.4.1</version>
        </dependency>

        <!--spring-mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.0</version>
            <exclusions>
                <exclusion>
                    <artifactId>mybatis</artifactId>
                    <groupId>org.mybatis</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
            <scope>compile</scope>
        </dependency>

三、创建前端查询实体

package com.example.dto;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;

/**
 * @version 1.0
 * @description:
 * @date 2023/3/29 14:54
 */
@Data
@JsonIgnoreProperties(ignoreUnknown = true) //忽略前端的传递的额外字段
public class OrderBySqlQuery {

    /**
     * 根据名称搜索
     */
    private String name;

    /**
     * 当前页
     */
    private Integer pageNum;

    /**
     * 每页大小
     */
    private Integer pageSize;

    /**
     * 排序的列字段
     */
    private String column;

    /**
     * 排序规则默认降序 降序:false 升序:true
     */
    private Boolean asc;

    public Boolean getAsc() {
        return asc == null ? false : asc;
    }
}

四、创建前端返回实体

package com.example.dto;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;

import java.math.BigDecimal;

/**
 * @version 1.0
 * @description:
 * @date 2023/3/29 14:54
 */
@Data
@JsonIgnoreProperties(ignoreUnknown = true) //忽略前端的传递的额外字段
public class OrderBySqlData {


    private Long id;

    /**
     * 名称
     */
    private String name;
    /**
     * 年龄
     */
    private int age;
    /**
     * 捐款
     */
    private BigDecimal fee;

    public OrderBySqlData() {
    }

    public OrderBySqlData(Long id, String name, int age,BigDecimal fee) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.fee = fee;
    }
}

五、定义mapper类

package com.example.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.dto.OrderBySqlData;

public interface OrderByDataMapper extends BaseMapper<OrderBySqlData> {

}

六、抽离工具类

package com.example.util;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description 对集合自定义排序
 * @Date: 上午10:27 2023/4/17
 */
@Slf4j
public class OrderForList {


    /**
     * 第一种写法 Java8
     * Java内存对list进行动态排序
     * 前端传入需要排序的字段,以及排序规则
     * 将对比的字段类型转换成double类型再进行对比 不支持中文
     * <p>
     * 
     *
     * @param t
     * @param sortFiled1 前端传入需要排序的字段
     * @param orderBy    排序规则 降序:false 升序:true
     * @param <T>
     * @return
     */
    public static <T> List<T> orderSort(List<T> t, String sortFiled1, Boolean orderBy) {
        if (CollectionUtils.isEmpty(t))
            return new ArrayList<>();
        if (StringUtils.isBlank(sortFiled1) || null == orderBy) {
            return t;
        }
        //将首字母大写
        String sortFiled = firstLetterName(sortFiled1);
        return t.stream().sorted((o1, o2) -> {
            try {
                double obj3 = 0;
                double obj4 = 0;
                //获取本类中的所有方法,包括私有的(private、protected、默认以及public)的方法
                Method methodOne = o1.getClass().getDeclaredMethod("get" + sortFiled);
                if (null != methodOne.invoke(o1)) {
                    //获取字段的值
                    String obj1 = String.valueOf(methodOne.invoke(o1));
                    if (StringUtils.isNotBlank(obj1) && StringUtils.isNotBlank(obj1.trim().replaceAll("\\,|\\.\\%", ""))) {
                        //特殊字符串处理 以及将字符串转成十进制的double类型数据
                        obj3 = Double.parseDouble(obj1.replaceAll("\\,|\\.\\%", ""));
                    }
                }
                Method methodTwo = o2.getClass().getDeclaredMethod("get" + sortFiled);
                if (null != methodTwo.invoke(o2)) {
                    String obj2 = String.valueOf(methodTwo.invoke(o2));
                    if (StringUtils.isNotBlank(obj2) && StringUtils.isNotBlank(obj2.trim().replaceAll("\\,|\\.\\%", ""))) {
                        //特殊字符串处理 以及将字符串转成十进制的double类型数据
                        obj4 = Double.parseDouble(obj2.replaceAll("\\,|\\.\\%", ""));
                    }
                }
                if (!orderBy) { //降序
                    return Double.compare(obj4, obj3);
                } else if (orderBy) { //升序
                    return Double.compare(obj3, obj4);
                }
            } catch (Exception e) {
                log.info("异常:" + e.getMessage());
            }
            return -1;
        }).collect(Collectors.toList());
    }

    /**
     * 第二种写法 Collections 工具类
     * Java内存对list进行动态排序
     * 前端传入需要排序的字段,以及排序规则
     * 将对比的字段类型转换成double类型再进行对比 不支持中文
     *
     * 优点:支持所有返回值字段(int,long,float,double,BigDecimal)排序
     * 缺点:只能内存排序,数据量大的时候效率极低
     *
     * @param t
     * @param sortFiled1 前端传入需要排序的字段
     * @param orderBy    排序规则 降序:false 升序:true
     * @param <T>
     * @return
     */
    public static <T> List<T> orderSortTwo(List<T> t, String sortFiled1, Boolean orderBy) {
        String sortFiled = firstLetterName(sortFiled1);
        Collections.sort(t, new Comparator<T>() {
            @Override
            public int compare(T o1, T o2) {
                double obj3 = 0;
                double obj4 = 0;
                try {
                    //获取本类中的所有方法,包括私有的(private、protected、默认以及public)的方法
                    Method methodOne = o1.getClass().getDeclaredMethod("get" + sortFiled);
                    //获取字段的值
                    String obj1 = String.valueOf(methodOne.invoke(o1));
                    if (StringUtils.isNotBlank(obj1) && StringUtils.isNotBlank(obj1.trim().replaceAll("\\,|\\.\\%", ""))) {
                        //特殊字符串处理 以及将字符串转成十进制的double类型数据
                        obj3 = Double.parseDouble(obj1.replaceAll("\\,|\\.\\%", ""));
                    }
                    Method methodTwo = o2.getClass().getDeclaredMethod("get" + sortFiled);
                    String obj2 = String.valueOf(methodTwo.invoke(o2));
                    if (StringUtils.isNotBlank(obj2) && StringUtils.isNotBlank(obj2.trim().replaceAll("\\,|\\.\\%", ""))) {
                        //特殊字符串处理 以及将字符串转成十进制的double类型数据
                        obj4 = Double.parseDouble(obj2.replaceAll("\\,|\\.\\%", ""));
                    }
                    if (!orderBy) { //降序
                        return Double.compare(obj4, obj3);
                    } else if (orderBy) { //升序
                        return Double.compare(obj3, obj4);
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }
                return 0;
            }
        });
        return t;
    }


    /**
     * 将传入的字符串首字母大写
     *
     * @param name
     * @return
     */
    public static String firstLetterName(String name) {
        char[] cs = name.toCharArray();
        cs[0] -= 32;
        return String.valueOf(cs);
    }

}

七、编写service

package com.example.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.example.dto.OrderBySqlData;
import com.example.dto.OrderBySqlQuery;
import com.example.mapper.OrderByDataMapper;
import com.example.util.HumpNamedUtils;
import com.example.util.OrderForList;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

/**
 * @Description 根据一个字段动态排序
 * @Date: 下午4:40 2023/4/17
 */
@Slf4j
public class OrderByService {

    @Autowired
    private OrderByDataMapper orderByDataMapper;

    /**
     * 根据前端传入的排序字段,以及排序规则
     * 使用MybatisPlus进行动态排序
     *
     * @param query
     * @return
     */
    public List OrderBySql(OrderBySqlQuery query) {
        QueryWrapper<OrderBySqlData> queryWrapper = new QueryWrapper<>();
        //将queryWrapper转为lambdaQueryWrapper,然后再进行条件搜索
        queryWrapper.lambda().eq(OrderBySqlData::getName, query.getName());
        //处理排序 升序
        if (StringUtils.isNotBlank(query.getColumn()) && query.getAsc()) {
            queryWrapper.orderByAsc(HumpNamedUtils.hump2LowerColumnName(query.getColumn()));
        }
        //处理排序 降序
        if (StringUtils.isNotBlank(query.getColumn()) && !query.getAsc()) {
            queryWrapper.orderByDesc(HumpNamedUtils.hump2LowerColumnName(query.getColumn()));
        }
        //查询数据库
        return orderByDataMapper.selectList(queryWrapper);
    }

    /**
     * 使用Java内存进行排序 第一种写法 Java8
     *
     * @param query
     * @return
     */
    public static void OrderByJava(OrderBySqlQuery query) {
        //模拟数据
        List<OrderBySqlData> orderBySqlData = Arrays.asList(new OrderBySqlData(1L, "张三", 12, BigDecimal.valueOf(100.5)), new OrderBySqlData(2L, "李四", 13, BigDecimal.valueOf(21.51)));
        List<OrderBySqlData> feeAsc = OrderForList.orderSort(orderBySqlData, query.getColumn(), query.getAsc());
        log.info("**************************第一种写法 Java8:" + JSON.toJSONString(feeAsc));
        List<OrderBySqlData> feeDesc1 = OrderForList.orderSortTwo(orderBySqlData, query.getColumn(), query.getAsc());
        log.info("**************************第二种写法 Collections 工具类:" + JSON.toJSONString(feeDesc1));
    }

}

八、测试

   /**
     * 测试
     *
     * @param args
     */
    public static void main(String[] args) {
        //根据捐款字段降序
        OrderBySqlQuery query = new OrderBySqlQuery();
        query.setColumn("fee");
        query.setAsc(false);
        OrderByJava(query);
        //根据捐款字段升序
        OrderBySqlQuery query1 = new OrderBySqlQuery();
        query1.setColumn("fee");
        query1.setAsc(true);
        OrderByJava(query1);
    }

结果:
在这里插入图片描述

九、开源仓库地址

Gitee仓库:https://gitee.com/Dev9925/custom-sorting-demo
GitHub仓库:

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值