mybatisPlus根据查询条件增加每页合计及总计工具类

原来项目的表格没有本页合计跟总计,但是最近这个客户需要再所有表格的最下方增加本页合计与总计,然后总结了下,本页合计就是把查到的数据是数字类型的加到一块,总计就是查询符合条件数据的总计,直接写个工具类,需要的时候调用一下方法就好了,简单省事.
先看效果
在这里插入图片描述

当需要返回本页合计与总计时只需要

    @RequestMapping(value = "/getByPage", method = RequestMethod.GET)
    @ApiOperation(value = "分页获取")
    @SystemLog(description = "其他消耗分页获取", type = LogType.OPERATION)
    public Result<IPage<SandConsumeVo>> getByPage(PageVo page, SandConsumeVo sandConsumeVo,SearchVo searchVo) {
    	//getQw为封装的查询条件方法,返回QueryWrapper
        QueryWrapper<SandConsume> qw = getQw(sandConsumeVo,searchVo);
        IPage<SandConsume> data = iSandConsumeService.page(PageUtil.initMpPage(page), qw);
        IPage<SandConsumeVo> result = objectToVoUtil.toPageVo(data, SandConsumeVo.class);
        SetTotal.setTotal(iSandConsumeService,qw,pageVo,SandConsumeVo.class,SandConsumeVo::getUseValue,SandConsumeVo::getCurrValue);
        //只添加本页合计则使用setPageTotal
        // SetTotal.setPageTotal(result,SandConsumeVo.class,SandConsumeVo::getUseValue,SandConsumeVo::getCurrValue);
        //只添加合计则使用setCountTotal
   	    //  SetTotal.setCountTotal(iSandConsumeService,qw,result,SandConsumeVo.class,SandConsumeVo::getUseValue,SandConsumeVo::getCurrValue);
        return new ResultUtil<IPage<SandConsumeVo>>().setData(result);
    }

接下来,看代码!!!

package cn.exrick.xboot.config.mybatisplus;

import cn.exrick.xboot.base.XbootBaseEntity;
import cn.exrick.xboot.common.constant.CommonConstant;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda;
import com.baomidou.mybatisplus.extension.service.IService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.ibatis.reflection.property.PropertyNamer;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author lcw
 * @description
 */
@Slf4j
@Component
public class SetTotal {

    /**
     *	自动在分页数据后增加本页合计与总计
     * @param service 查询的service
     * @param qw 查询的条件
     * @param result 返回的分页数据
     * @param voClass 返回的类的类型
     * @param propertys 哪些字段需要求和以及查询数据库求和
     * @param <T> 返回的Vo类
     * @param <V> 查询的实体类
     */
    public static  <T,V> void setTotal(IService<V> service,QueryWrapper<V> qw, IPage<T> result,Class<?> voClass, SFunction<? super T, ?>... propertys) {
        //本页合计
        List<String> columns = new ArrayList<>();
        List<String> propertyArr = new ArrayList<>();
        List<T> records = result.getRecords();
        try{
        T count = (T) voClass.newInstance();
        //CommonConstant是本页合计还是总计的枚举类,需要根据自己的情况自己设置
        setDataFlag(count, CommonConstant.DATA_FLAG_COUNT);
        T page = (T) voClass.newInstance();
        setDataFlag(page, CommonConstant.DATA_FLAG_PAGE);
        for ( SFunction<? super T, ?> property: propertys) {
            SerializedLambda lambda = SerializedLambda.resolve(property);
            String fieldName = PropertyNamer.methodToProperty(lambda.getImplMethodName());
            columns.add(to_(fieldName));
            propertyArr.add(fieldName);
            BigDecimal value = records.stream()
                            .map(
                                    one ->
                                            ObjectUtils.isEmpty(property.apply(one))
                                                    ? BigDecimal.ZERO
                                                    : new BigDecimal(String.valueOf(property.apply(one))))
                            .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(3,BigDecimal.ROUND_HALF_UP);
            try{
                setProperty(property,value,page);
            }catch (Exception e){
                log.error("赋值失败,",fieldName);
            }
        }
        records.add(page);
        //查询总合计
         String select =
                 columns.stream()
                        .map(item -> String.format(FORMAT, StrUtil.toUnderlineCase(item), item))
                        .collect(Collectors.joining(","));
         qw.select(select);
        V one = service.getOne(qw);
        for (String property :propertyArr ) {
            Class<?> queryClazz = one.getClass();
            Field field = getField(queryClazz,property);
            Object o = null;
            try{
                field.setAccessible(true);
                o = field.get(one);
            }catch (Exception e){
                o = "0";
            }
            Class<?> fieldType = field.getType();
            Class<?> updateClazz = count.getClass();
            Field updateField = getField(updateClazz,property);
            try{
                setProperty(updateField,convert(o,fieldType),count);
            }catch (Exception e){
                log.error("赋值失败,",property);
            }
        }
        records.add(count);
        }catch (Exception e){
            e.printStackTrace();
            log.error("创建对象失败,");
        }
    }

    /**
     * 往返回数据后增加总计
     * @param service 查询的service
     * @param qw 查询的条件
     * @param result 返回的分页数据
     * @param voClass 返回的类的类型
     * @param propertys 哪些字段需要求和以及查询数据库求和
     * @param <T> 返回的Vo类
     * @param <V> 查询的实体类
     */
    public static  <T,V> void setCountTotal(IService<V> service,QueryWrapper<V> qw, IPage<T> result,Class<?> voClass, SFunction<? super T, ?>... propertys) {
        //本页合计
        List<String> columns = new ArrayList<>();
        List<String> propertyArr = new ArrayList<>();
        List<T> records = result.getRecords();
        try{
            T count = (T) voClass.newInstance();
            setDataFlag(count, CommonConstant.DATA_FLAG_COUNT);
            //查询总合计
            String select =
                    columns.stream()
                            .map(item -> String.format(FORMAT, StrUtil.toUnderlineCase(item), item))
                            .collect(Collectors.joining(","));
            qw.select(select);
            V one = service.getOne(qw);

            for (String property :propertyArr ) {
                Class<?> queryClazz = one.getClass();
                Field field = getField(queryClazz,property);
                Object o = null;
                try{
                    field.setAccessible(true);
                    o = field.get(one);
                }catch (Exception e){
                    o = "0";
                }
                Class<?> fieldType = field.getType();
                Class<?> updateClazz = count.getClass();
                Field updateField = getField(updateClazz,property);
                try{
                    setProperty(updateField,convert(o,fieldType),count);
                }catch (Exception e){
                    log.error("赋值失败,",property);
                }
            }
            records.add(count);

        }catch (Exception e){
            e.printStackTrace();
            log.error("创建对象失败,");
        }
    }

    /**
     * 向返回数据中增加本页合计
     * @param result 返回的分页数据
     * @param voClass 返回的分页类型
     * @param propertys 需要计算的字段
     * @param <T> 返回的Vo类
     */
    public static  <T> void setPageTotal( IPage<T> result,Class<?> voClass, SFunction<? super T, ?>... propertys) {
        //本页合计
        List<String> columns = new ArrayList<>();
        List<String> propertyArr = new ArrayList<>();
        List<T> records = result.getRecords();
        try{
            T page = (T) voClass.newInstance();
            setDataFlag(page, CommonConstant.DATA_FLAG_PAGE);
            for ( SFunction<? super T, ?> property: propertys) {
                SerializedLambda lambda = SerializedLambda.resolve(property);
                String fieldName = PropertyNamer.methodToProperty(lambda.getImplMethodName());
                columns.add(to_(fieldName));
                propertyArr.add(fieldName);
                BigDecimal value = records.stream()
                        .map(
                                one ->
                                        ObjectUtils.isEmpty(property.apply(one))
                                                ? BigDecimal.ZERO
                                                : new BigDecimal(String.valueOf(property.apply(one))))
                        .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(3,BigDecimal.ROUND_HALF_UP);
                try{
                    setProperty(property,value,page);
                }catch (Exception e){
                    log.error("赋值失败,",fieldName);
                }
            }
            records.add(page);
        }catch (Exception e){
            e.printStackTrace();
            log.error("创建对象失败,");
        }
    }

    //注意,此处需要自己改成本页合计还是总计的标志,我的vo类里是dataFlag字段
    public static <T> void setDataFlag(T t,Integer type){
        Class<?> updateClazz = t.getClass();
        Field field = getField(updateClazz,"dataFlag");
        try{
            setProperty(field,type,t);
        }catch (Exception e){
            log.error("dataFlag赋值失败");
        }
    }
    private static final String FORMAT = " ifnull(sum(%s),0) as %s ";

    private static final Pattern TPATTERN = Pattern.compile("[A-Z0-9]");
    private static String to_(String str) {
        Matcher matcher = TPATTERN.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    public static <T> void setProperty(SFunction<? super T, ?> property,Object value,T t) throws IllegalAccessException {
        SerializedLambda lambda = SerializedLambda.resolve(property);
        //获取要修改的字段
        String fieldName = PropertyNamer.methodToProperty(lambda.getImplMethodName());
        Class<?> updateClazz = t.getClass();
        //修改字段,如果此类找不到该属性则查找父类
        Field field = getField(updateClazz,fieldName);
        // 设置字段访问权限,允许私有字段访问
        field.setAccessible(true);
        // 给字段设置值
        Class<?> fieldType = field.getType();
        field.set(t,  convert(value,fieldType));
    }

    public static <T> void setProperty(Field field ,Object value,T t) throws IllegalAccessException {

        // 设置字段访问权限,允许私有字段访问
        field.setAccessible(true);
        // 给字段设置值
        Class<?> fieldType = field.getType();
        field.set(t,  convert(value,fieldType));
    }

    public static  Field getField(Class<?> clazz,String fieldName){
        try{
            Field declaredField = clazz.getDeclaredField(fieldName);
            return declaredField;
        }catch (NoSuchFieldException e){
            Class<?> superclass = clazz.getSuperclass();
         return   getField(superclass,fieldName);
        }
    }

    public static <T> T convert(Object o, Class<T> tClass) {
        if (o == null) {
            return null;
        }
        initConvert();
        for (Convert convert : convertList) {
            if(convert.support(tClass)){
                T t = (T) convert.parse(o);
                return t;
            }
        }
        log.error("没有适配的转换器["+tClass+"]");
        return null;
    }

    public interface Convert<T> {
        boolean support(Class<?> tClass);
        T parse(Object o);
    }

    private static List<Convert> convertList = new ArrayList<>();
    public static List<Convert> initConvert(){
        if(convertList.isEmpty()){
            SetTotal st = new SetTotal();
            convertList.add(st.new StringConvert());
            convertList.add(st.new IntegerConvert());
            convertList.add(st.new BigDecimalConvert());
            convertList.add(st.new DoubleBConvert());
        }

        return convertList;
    }
    public class IntegerConvert implements Convert<Integer>{
        @Override
        public boolean support(Class<?> tClass) {
            return tClass == Integer.class;
        }

        @Override
        public Integer parse(Object o) {
            if(o==null) return null;

            if(o instanceof String){
                if("".equals(o)) return null;
                return new Integer((String)o);
            }else if(o instanceof Integer){
                return (Integer)o;
            }else if(o instanceof BigDecimal){
                return ((BigDecimal) o).intValue();
            }else {
                throw new RuntimeException(o.getClass()+"不能转换为Integer"+", 值为["+o+"]");
            }
        }
    }

    public class StringConvert implements Convert<String>{
        @Override
        public boolean support(Class<?> tClass) {
            return tClass == String.class;
        }

        @Override
        public String parse(Object o) {
            if(o==null) return null;

            if(o instanceof String){
                return (String)o;
            }else if(o instanceof Integer){
                return String.valueOf(o);
            }else if(o instanceof BigDecimal){
                return ((BigDecimal) o).toString();
            }else {
                if(o instanceof Map){
                    // 特殊日期处理
//                {"date":"2021-04-25 11:47:40.000000","timezone_type":3,"timezone":"PRC"}
                    Map map = (Map) o;
                    if(map.keySet().contains("date")&&map.keySet().contains("timezone_type")&&map.keySet().contains("timezone")){
                        String str = (String) map.get("date");
                        if(str.length()>19){
                            return str.substring(0, 19);
                        }else{
                            return str;
                        }

                    }
                }
                throw new RuntimeException(o.getClass()+"不能转换为String"+", 值为["+o+"]");
            }
        }
    }

    public class BigDecimalConvert  implements Convert<BigDecimal> {
        @Override
        public boolean support(Class<?> tClass) {
            return tClass == BigDecimal.class;
        }

        @Override
        public BigDecimal parse(Object o) {
            if(o==null) return null;
            // 字符串转
            // 数字转
            if(o instanceof String){
                return new BigDecimal((String)o);
            }else if(o instanceof Integer){
                return new BigDecimal((Integer)o);
            }else if(o instanceof BigDecimal){
                return (BigDecimal) o;
            }else {
                throw new RuntimeException(o.getClass()+"不能转换为BigDecimal"+", 值为["+o+"]");
            }

        }
    }

    public class DoubleBConvert implements Convert<Double>{
        @Override
        public boolean support(Class<?> tClass) {
            return tClass == Integer.class;
        }

        @Override
        public Double parse(Object o) {
            if(o==null) return null;

            if(o instanceof String){
                if("".equals(o)) return null;
                return new Double((String)o);
            }else if(o instanceof Integer){
                return (Double)o;
            }else if(o instanceof BigDecimal){
                return ((BigDecimal) o).doubleValue();
            }else {
                throw new RuntimeException(o.getClass()+"不能转换为Integer"+", 值为["+o+"]");
            }
        }
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值