Java calcula la fecha y la hora continuas y completa el valor predeterminado de los datos de fecha que faltan en la interfaz estadística

Escenario empresarial: en algunas estadísticas, necesitamos realizar consultas estadísticas sobre los datos existentes del sistema dentro de un cierto período de tiempo, pero los datos existentes en nuestro sistema empresarial pueden estar saltando fechas. Pero los datos que devolvemos al front-end son para completar con ceros las fechas que faltan.

Esta situación en realidad se puede abstraer como un comportamiento.Este artículo usa localDate y reflexión para escribir una clase de herramienta para manejar esta situación convenientemente.

1. Visualización de efectos

Aquí mostramos el llenado de clases estadísticas de vo con dos dimensiones completamente diferentes (una basada en estadísticas de mes y otra basada en estadísticas de fecha), y los campos de las dos clases de vo también son completamente diferentes, pero la clase de herramienta puede ser muy buena para Su paso de parámetros es compatible con
1.1 Según las estadísticas de fecha
, se puede ver que antes solo había un dato. Después de llenar, se convierte en el dato de fechas continuas.
inserte la descripción de la imagen aquí

1.2 Estadísticas basadas en el mes
Se puede ver que antes solo había un dato. Después del llenado, se convierte en los datos de meses consecutivos.
inserte la descripción de la imagen aquí

2. Ideas de diseño

Ideas de desarrollo y diseño:
1. Primero calcule la fecha continua intermedia dateList de acuerdo con la "fecha de inicio" y la "fecha de finalización"
2. Convierta los datos mysqlDataList de las estadísticas de la base de datos al formato de Map<String, T>, la clave es la fecha, y el val es en sí mismo. Aquí se llama mysqlDataListToMap
2. Recorra esta lista de fechas, y cada elemento atravesado se llama timeStr
2.1 Si el timeStr calculado existe en mysqlMap, omita
2.2 Si este timeStr no existe en mysqlMap, significa que debemos completar la fecha correspondiente faltante data
3. Construya dinámicamente datos para campos de acuerdo con la reflexión

El código se mostrará directamente debajo. Hay comentarios en el código. Si tiene alguna pregunta, comuníquese en el área de comentarios.

3. Visualización de código

3.1 Herramientas

package com.lzq.learn.test.构造假数据;

import cn.hutool.core.util.StrUtil;
import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 润色数据,补充数据库中的没有统计到的月份填充值
 *
 * @author LiuZhiQiang
 */
public class BuildDateDataUtil {
    
    


    /**
     * <p>@Description: 对于时间范围内的数据进行连续时间填充</p >
     * <p>@param [mysqlDataList 从MySQL查询到的数据List, startTime 开始时间, endTime 结束时间, type 类型:(年, 月, 日) ]</p >
     * <p>@return java.util.List<T></p >
     * <p>@throws </p >
     * <p>@author LiuZhiQiang</p >
     * <p>@date 11:35 11:35</p >
     */
    public static <T> List<T> addMissDateData(List<T> mysqlDataList, LocalDate startDate, LocalDate endDate, String type, Map<String, Object> fakeFieldAndFieldValue, Class<T> dataClass, String timeFieldName) throws Exception {
    
    
        // 进行日期list的计算
        List<String> dateList = BuildDateDataUtil.computeDateList(type, startDate, endDate);
        LinkedHashMap<String, T> mysqlDataListToMap = new LinkedHashMap<>();
        for (T t : mysqlDataList) {
    
    
            Class<?> objClass = t.getClass();
            Field declaredField = objClass.getDeclaredField(timeFieldName);
            declaredField.setAccessible(true);
            String timeStr = (String) declaredField.get(t);
            mysqlDataListToMap.put(timeStr, t);
        }
        List<T> finalResultList = new ArrayList<>();
        // 返回给前端数据润色
        for (String timeStr : dateList) {
    
    
            if (mysqlDataListToMap.containsKey(timeStr)) {
    
    
                finalResultList.add(mysqlDataListToMap.get(timeStr));
                continue;
            }
            fakeFieldAndFieldValue.put(timeFieldName, timeStr);
            T resultItem = BuildDateDataUtil.makeFakeData(fakeFieldAndFieldValue, dataClass);
            finalResultList.add(resultItem);
        }
        return finalResultList;
    }

    /**
     * <p>@Description: 根据type和startDate和endDate来进行计算 日期List</p >
     * <p>@param [type 日期间隔类型:年,月,日, startDate 开始日期, endDate 结束日期]</p >
     * <p>@return 连续间隔的日期列表</p >
     * <p>@throws </p >
     */
    public static List<String> computeDateList(String type, LocalDate startDate, LocalDate endDate) {
    
    
        int index = 9999;
        List<String> dateList = new ArrayList<>();
        int i = 0;
        if (StrUtil.equals(type, "month")) {
    
    
            startDate = LocalDate.of(startDate.getYear(), startDate.getMonthValue(), 1);
            endDate = LocalDate.of(endDate.getYear(), endDate.getMonthValue(), 1);
            dateList.add(startDate.format(DateTimeFormatter.ofPattern("yyyy-MM")));
            while (startDate.isBefore(endDate)) {
    
    
                if (i >= index) {
    
    
                    throw new RuntimeException("程序错误:陷入了死循环");
                }
                startDate = startDate.plusMonths(1);
                dateList.add(startDate.format(DateTimeFormatter.ofPattern("yyyy-MM")));
                i++;
            }
        }
        if (StrUtil.equals(type, "year")) {
    
    
            startDate = LocalDate.of(startDate.getYear(), 1, 1);
            endDate = LocalDate.of(endDate.getYear(), 1, 1);
            dateList.add(startDate.format(DateTimeFormatter.ofPattern("yyyy")));
            while (startDate.isBefore(endDate)) {
    
    
                if (i >= index) {
    
    
                    throw new RuntimeException("程序错误:陷入了死循环");
                }
                startDate = startDate.plusYears(1);
                dateList.add(startDate.format(DateTimeFormatter.ofPattern("yyyy")));
                i++;
            }
        }
        if (StrUtil.equals(type, "day")) {
    
    
            // 深拷贝
            startDate = LocalDate.of(startDate.getYear(), startDate.getMonthValue(), startDate.getDayOfMonth());
            endDate = LocalDate.of(endDate.getYear(), endDate.getMonthValue(), endDate.getDayOfMonth());
            dateList.add(startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            while (startDate.isBefore(endDate)) {
    
    
                if (i >= index) {
    
    
                    throw new RuntimeException("程序错误:陷入了死循环");
                }
                startDate = startDate.plusDays(1);
                dateList.add(startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
                i++;
            }
        }
        return dateList;
    }


    // :
    /**
     * <p>@Description: 根据 fieldAndFieldValue 进行实例化假数据</p >
     * <p>@param [fieldAndFieldValue 需要进行填充的字段以及字段值, dataClass 实例化的class模板]</p >
     * <p>@return 填充数据后的实例化对象</p >
     */
    public static <T> T makeFakeData(Map<String, Object> fieldAndFieldValue, Class<T> dataClass) throws Exception {
    
    
        // 利用反射进行 字段值的填充
        T fakeData = dataClass.newInstance();
        // 2.通过迭代器遍历map
        Iterator<Map.Entry<String, Object>> iterator = fieldAndFieldValue.entrySet().iterator();
        while (iterator.hasNext()) {
    
    
            Map.Entry<String, Object> entry = iterator.next();
            Field declaredField = fakeData.getClass().getDeclaredField(entry.getKey());
            declaredField.setAccessible(true);
            declaredField.set(fakeData, entry.getValue());
        }
        return fakeData;
    }
}

3.2 Clase estadística VO

3.2.1 Estadísticas de productos Categoría VO


package com.lzq.learn.test.构造假数据;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;

/**
 * <p>@Description: 商品统计vo类</p >
 * <p>@author lzq</p >
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class GoodStatistic {
    
    

    // 日期,例如:2023-01-01
    private String dateString;

    // 购买次数
    private BigDecimal count;
    
}

3.2.2 Estadísticas de órdenes Clase VO

package com.lzq.learn.test.构造假数据;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;

/**
 * <p>@Description: 订单统计vo类</p >
 * <p>@author lzq</p >
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OrderStatistic {
    
    

    // 月份,例如:2023-02
    private String monthString;

    // 交易订单累计金额
    private BigDecimal money;

}

3.3 Clase de prueba, casos de uso

package com.lzq.learn.test.构造假数据;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
/**
 * <p>@Description: 构造假数据测试类</p >
 * @author lzq
 */
public class TestMain {
    
    

    public static void main(String[] args) throws Exception {
    
    
        // 1.统计商品信息
        GoodsTest();
        // 2.统计订单信息
        OrderTest();

    }

    // 测试 GoodStatistic 填充假数据
    public static void GoodsTest() throws Exception {
    
    
        ArrayList<GoodStatistic> mysqlList = new ArrayList<>();
        // 模拟从mysql查询数据
        mysqlList.add(new GoodStatistic("2023-02-25", BigDecimal.TEN));
        LocalDate startDate = LocalDate.of(2023,2,24);
        LocalDate endDate = LocalDate.of(2023,3,5);
        LinkedHashMap<String, Object> fillFakeDataMap = new LinkedHashMap<>();
        fillFakeDataMap.put("dateString", null);
        fillFakeDataMap.put("count", BigDecimal.ZERO);
        List<GoodStatistic> finalList = BuildDateDataUtil.addMissDateData(mysqlList, startDate, endDate, "day", fillFakeDataMap,
                GoodStatistic.class, "dateString");
        finalList.forEach(System.out::println);
    }

    // 测试 OrderStatistic 填充假数据
    public static void OrderTest() throws Exception {
    
    
        ArrayList<OrderStatistic> mysqlList = new ArrayList<>();
        // 模拟从mysql查询数据
        mysqlList.add(new OrderStatistic("2023-02", BigDecimal.TEN));
        LocalDate startDate = LocalDate.of(2023,2,1);
        LocalDate endDate = LocalDate.of(2023,6,1);
        LinkedHashMap<String, Object> fillFakeDataMap = new LinkedHashMap<>();
        fillFakeDataMap.put("monthString", null);
        fillFakeDataMap.put("money", BigDecimal.ZERO);
        List<OrderStatistic> finalList = BuildDateDataUtil.addMissDateData(mysqlList, startDate, endDate, "month", fillFakeDataMap,
                OrderStatistic.class, "monthString");
        finalList.forEach(System.out::println);
    }
}

Resumen: el código central de este artículo es en realidad calcular el tiempo continuo en función de la "fecha de inicio" y la "fecha de finalización "
.

Si tiene alguna pregunta, puede dejar un mensaje en el área de comentarios y le responderé a tiempo cuando lo vea.

Supongo que te gusta

Origin blog.csdn.net/lzq2357639195/article/details/131749896
Recomendado
Clasificación