首页 > 编程语言 >java实现一组数据计算同比环比(终极版)

java实现一组数据计算同比环比(终极版)

时间:2023-03-16 12:23:37浏览次数:51  
标签:终极版 java String 一组 format return import public

本篇基于下面两篇博客的内容整合实现:

java实现一组数据计算同比环比

CGLIB基于一个已有类动态生成一个子类bean(转)

之前的博客中已经捋清了在只有日期和一列数据的情况下动态生成环比、同步数据的逻辑,

但只是一个demo,本次要在生产环境使用,就要进行进一步的改造。

首先我们定义一个注解,标记那个方法需要进行增强处理,month指定日期列,value就是数据列,limit指定要保留的行数

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateGenerator {
String month();
String value();
int limit();

}

然后我们定义一个AOP,在有上面注解的地方进行拦截处理

@Slf4j
@Component
@Aspect
public class RateGeneratorAOP {

    @Pointcut("@annotation(com.pangu.utils.format.RateGenerator)")
    public void ServiceAspect() {
    }

    @Autowired
    private RateGeneratorProcessor processor;


    @Around("ServiceAspect()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) {
        Object[] args = proceedingJoinPoint.getArgs();
        MethodSignature signature =(MethodSignature) proceedingJoinPoint.getSignature();
        Method method = signature.getMethod();
        RateGenerator annotation = method.getAnnotation(RateGenerator.class);
        Object proceed = null;
        List<Object> newResultList=null;
        try {
            proceed = proceedingJoinPoint.proceed(args);
            if(proceed instanceof List&& annotation!=null){
                List<Object> resultList = (List<Object>) proceed;
                 newResultList = processor.process(resultList, annotation);
            }
        } catch (Throwable e) {
            log.error(e.getMessage());
        }
        return newResultList;

    }
}

当然核心代码就在processor里面,processor的逻辑不复杂

1.拿到原始数据,根据指定的日期列和数据列,收集成一个map

2.对应每一行数据的日期,计算得到上月日期和去年同月日期,并从map中获取对应value

3.计算同比、环比,分母为零时,同比环比也设为0

4.基于旧object建立动态bean,target,将新生成的同步、环比放进target中

5.将target保留最后几个元素后返回

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author : wangbin
 * @Date : 2023/3/16 9:22
 * @Description:
 */
@Slf4j
@Service
public class RateGeneratorProcessor {
    private static final java.text.DecimalFormat decimalFormat = new java.text.DecimalFormat("#.##");
    private static final java.text.DecimalFormat decimalFormatV3 = new java.text.DecimalFormat("#.###");
    public List<Object> process(List<Object> objectList,RateGenerator annotation) throws IllegalAccessException {
        Map<String, Double> map = new HashMap<>();
        Map<Object, Tuple> objectMap = new HashMap<>();
        String monthFieldName = annotation.month();
        String valueFieldName = annotation.value();
        int limit = annotation.limit();
        int size = objectList.size();
        Class<?> aClass = objectList.get(0).getClass();
        for (Object o : objectList) {
            Tuple tuple = new Tuple();
            Field[] fields = aClass.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                if(field.getName().equals(monthFieldName)){
                    tuple.setMonth(field.get(o).toString());
                }
                if(field.getName().equals(valueFieldName)){
                    tuple.setValue(field.get(o).toString());
                }
            }
            objectMap.put(o,tuple);
            map.put(tuple.getMonth(),Double.parseDouble( tuple.getValue()));
        }


        return objectList.stream().map(o -> {
            Tuple tuple = objectMap.get(o);

            String key = tuple.getMonth();
            Double value = Double.valueOf(tuple.getValue());
            String lastMonth = getLastMonth(key);
            String lastYearMonth = getLastYearMonth(key);
            Double basisRate = basisRate(map.getOrDefault(lastYearMonth, 0d), value);
            Double loopRate = basisRate(map.getOrDefault(lastMonth, 0d), value);
            Map<String, Object> newMap = new HashMap<>();
            //百分比保留两位小数
            newMap.put("tb", decimalFormat.format(basisRate));
            newMap.put("hb", decimalFormat.format(loopRate));
            return DynamicBean.getTarget(o, newMap);
        }).skip(size - limit).collect(Collectors.toList());

    }


    @Data
    static class Tuple{
        String month;
        String value;
    }


    public static Double basisRate(Double lastVal,Double thisVal){
        if(lastVal==null||lastVal==0d){
            return 0d;
        }
        return 100*(thisVal-lastVal)/lastVal;
    }

    //上月
    public  String getLastMonth(String month){
        DateTimeFormatter format = new DateTimeFormatterBuilder()
                .appendPattern("yyyy-MM")
                .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
                .toFormatter();
        LocalDate parse = LocalDate.from(format.parse(month));
        LocalDate lastMonth = parse.minusMonths(1);
        return format.format(lastMonth);
    }

    //去年同月
    public  String getLastYearMonth(String month){
        DateTimeFormatter format = new DateTimeFormatterBuilder()
                .appendPattern("yyyy-MM")
                .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
                .toFormatter();
        LocalDate parse = LocalDate.from(format.parse(month));
        LocalDate lastMonth = parse.minusYears(1);
        return format.format(lastMonth);
    }
}

最后是动态bean的生成,使用了spring的cglib包

import org.apache.commons.beanutils.PropertyUtilsBean;
import org.springframework.cglib.beans.BeanGenerator;
import org.springframework.cglib.beans.BeanMap;

import java.beans.PropertyDescriptor;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author : wangbin
 * @Date : 2023/3/16 9:12
 * @Description:
 */
public class DynamicBean {
    /**
     * 目标对象
     */
    private Object target;
    /**
     * 属性集合
     */
    private BeanMap beanMap;

    public DynamicBean(Class superclass, Map<String, Class> propertyMap) {
        this.target = generateBean(superclass, propertyMap);
        this.beanMap = BeanMap.create(this.target);
    }

    /**
     * bean 添加属性和值
     *
     * @param property
     * @param value
     */
    public void setValue(String property, Object value) {
        beanMap.put(property, value);
    }

    /**
     * 获取属性值
     *
     * @param property
     * @return
     */
    public Object getValue(String property) {
        return beanMap.get(property);
    }

    /**
     * 获取对象
     *
     * @return
     */
    public Object getTarget() {
        return this.target;
    }

    /**
     * 根据属性生成对象
     *
     * @param superclass
     * @param propertyMap
     * @return
     */
    private Object generateBean(Class superclass, Map<String, Class> propertyMap) {
        BeanGenerator generator = new BeanGenerator();
        if (null != superclass) {
            generator.setSuperclass(superclass);
        }
        BeanGenerator.addProperties(generator, propertyMap);
        return generator.create();
    }

    public static Object getTarget(Object dest, Map<String, Object> addProperties) {
        // 获取属性map
        PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
        PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(dest);
        Map<String, Class> propertyMap = new HashMap<>();
        for (PropertyDescriptor d : descriptors) {
            if (!"class".equalsIgnoreCase(d.getName())) {
                propertyMap.put(d.getName(), d.getPropertyType());
            }
        }
        // 添加新属性
        addProperties.forEach((k, v) -> propertyMap.put(k, v.getClass()));
        // 创建动态bean
        DynamicBean dynamicBean = new DynamicBean(dest.getClass(), propertyMap);
        // 给bean添加旧数据
        propertyMap.forEach((k, v) -> {
            try {
                if (!addProperties.containsKey(k)) {
                    dynamicBean.setValue(k, propertyUtilsBean.getNestedProperty(dest, k));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        // 添加新数据
        addProperties.forEach((k, v) -> {
            try {
                dynamicBean.setValue(k, v);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        return dynamicBean.getTarget();
    }
}

 

标签:终极版,java,String,一组,format,return,import,public
From: https://www.cnblogs.com/wangbin2188/p/17222088.html

相关文章

  • JavaIO中直接内存的使用
    注:本文转自:https://www.toutiao.com/article/7198357822390977080/?log_from=ed0bb42919105_1678896533085本次分享主要由io与nio读取文件速度差异的情况,去了解nio为什么......
  • day94-javaweb-servlet路径问题
    servlet路径问题在web.xml中设置不同映射走的对应的路径<!--可以自定义后缀实现请求路径注意:*前面不能加项目映射的路径hello/sasasas.ggugu......
  • JavaBean
    实体类JavaBean有特定的写法:●必须要有一个无参构造●属性必须私有化●必须有对应的get/set方法一般用来和数据库的字段做映射:ORMORM:对象关系映射●表-->类●字段-->......
  • day93- javaweb-servlet学习
    javaweb的Servlet1.下载maven,tomcat试了10版本的tomcat,好像不兼容,果断放弃安装了tomcat9,就成功了,真是神奇,高了我半天查了各种攻略,tomcat10确实是bug一堆2.从maven中导......
  • java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
    在一个servlet中连接数据库,加载驱动报错,将异常抛了出来。  解决方案:创建的Maven项目中,在web.xml中引入了mysql的驱动,但是创建的servlet需要使用Tomcat服务器,Tomcat中......
  • java_int数组转byte数组的一种方法
    Java:int数组转byte数组的一种方法记录一种int数组转byte数组的方法,无意中看到的。之前都是通过移位操作完成的,现在发现通过系统API就能实现:packagecom.yongdami.test......
  • Java 使用 ResourceBundle 类读取 properties 文件中文乱码的解决方案
    Java使用ResourceBundle类读取properties文件中文乱码的解决方案https://www.cnblogs.com/poterliu/p/10159577.htmlJava使用java.util.ResourceBundle类的方式来......
  • Java中的BigDecimal运算
    BigDecimal是Java中的一个高精度数值类型,它可以用于处理需要高精度计算的场景,例如财务计算。在进行加减乘除运算时,BigDecimal提供了多种方法。下面是几个示例:1.加法Big......
  • cannot access class org.springframework.cglib.core.ReflectUtils with java 17
    (inmodulecom.xxx)cannotaccessclassorg.springframework.cglib.core.ReflectUtils(inunnamedmodule@0x2d950574)becausemodulecom.xxxdoesnotreadunname......
  • 代码随想录算法训练营第一天| javascript |二分查找_LeetCode704, 移除元素_LeetCode2
    二分查找题目链接:https://leetcode.cn/problems/binary-search/文章讲解:https://programmercarl.com/0704.%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.html视频讲解:ht......