柱状图展示异步统计数据

文章描述了一个使用SpringBoot框架开发的Web服务控制器,用于网格数据的统计,包括网格数量和网格人员数量。通过Controller层调用Service层的异步方法,获取数据后,进行处理并返回JSON格式的结果。Mapper层负责与数据库交互,查询原始数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PC端

 APP端

 Controller层

package com.cnpc.dj.party.controller;

import com.alibaba.fastjson.JSONObject;
import com.cnpc.dj.common.JsonResult;
import com.cnpc.dj.common.context.BaseContextHandler;
import com.cnpc.dj.common.utils.DateUtils;
import com.cnpc.dj.party.common.ReturnExamEnum;
import com.cnpc.dj.party.service.GridDataStatisticService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;

@Slf4j
@CrossOrigin
@RestController
@RequestMapping("/dataStatistic")
public class GridDataStatisticController {

    @Autowired
    private GridDataStatisticService gridDataStatisticService ;

    @PostMapping("/doStatisticForGrid")
    public JsonResult<?> doStatisticForGrid(@RequestBody JSONObject requestBody) {
        // 检查入参合法性.
        BigDecimal orgId = requestBody.getBigDecimal("orgId");
        if (Objects.isNull(orgId)) {
            return JsonResult.error(ReturnExamEnum.GRID_ILLEGAL_ARGUMENT, "必要参数<orgId>未填写");
        }
        BigDecimal tenantId = BaseContextHandler.getDecimalTenantId();
        long beginTime = System.currentTimeMillis();
        log.info("\n[ {} ][ 网格员 - 数据统计任务 ]: 开始所有任务(当前租户ID: {} ).", DateUtils.format(new Date(beginTime), "yyyy年MM月dd日 HH时mm分ss秒 SSS毫秒"), tenantId);

        // 创建统计结果容器.
        JSONObject result = new JSONObject();

        // 创建异步统计任务: 调用各统计方法.
        CompletableFuture<?> task1 = gridDataStatisticService.gridNumberAsyncStatistic(tenantId, orgId, result);
        CompletableFuture<?> task2 = gridDataStatisticService.gridPersonNumberAsyncStatistic(tenantId, orgId, result);


        // 等待, 直到所有任务执行完毕.
        CompletableFuture.allOf(task1,task2).join();
        long endTime = System.currentTimeMillis();
        log.info("\n[ {} ][ 网格员 - 数据统计任务 ]: 所有任务完成, 总计耗时 {} 毫秒.", DateUtils.format(new Date(endTime), "yyyy年MM月dd日 HH时mm分ss秒 SSS毫秒"), endTime - beginTime);
        // 返回统计结果.
        return JsonResult.success(result);
    }
}

Service层 

package com.cnpc.dj.party.service;


import com.alibaba.fastjson.JSONObject;
import com.cnpc.dj.common.utils.DateUtils;
import com.cnpc.dj.party.common.EChartsResult;
import com.cnpc.dj.party.common.KeyValuePair;
import com.cnpc.dj.party.repository.GridDataStatisticMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;

@Service
@Slf4j
public class GridDataStatisticService {

    @Autowired
    private GridDataStatisticMapper gridDataStatisticMapper;

    private static String convert(long timeMillis) {
        return DateUtils.format(new Date(timeMillis), "yyyy年MM月dd日 HH时mm分ss秒 SSS毫秒");
    }

    /**
     * 获取网格信息
     * @param orgId 入参: 组织ID.
     * @return 统计结果.
     */
    @Async
    public CompletableFuture<?> gridNumberAsyncStatistic(BigDecimal tenantId, BigDecimal orgId, JSONObject parent) {
        long t0 = System.currentTimeMillis();
        log.info("\n[ {} ][ 网格情况 ][ 网格数量统计 ]: 任务开始.", convert(t0));
        // 查询数据库, 获取原始数据
        List<KeyValuePair<BigDecimal>> list = gridDataStatisticMapper.statisticGrid(tenantId, orgId);
        long t1 = System.currentTimeMillis();
        log.info("\n[ {} ][ 网格情况 ][ 网格数量统计 ]: 原始数据查询成功: 本步耗时 {} 毫秒, 总计耗时 {} 毫秒.", convert(t1),t1 - t0,t1 - t0);

        // 初始化查询结果容器.
        // 初始化查询结果容器.管理类,科研类,生产经营类,项目建设类,生产作业类,网格总数
        String[] mapEntry = {"Manage", "Scientific", "ProductionOperation", "ProjectBuild","FlowHomework", "GridTotal"};
        EChartsResult result = new EChartsResult();
        result.init(null, mapEntry, null);
        BigDecimal gridTotal = BigDecimal.ZERO;
        // 处理原始数据, 填充查询结果容器.
        for (KeyValuePair<BigDecimal> item : list) {
            if (Objects.nonNull(item.getKey())) {
                switch (item.getKey()) {
                    case "1":
                        result.addToMap(mapEntry[0], item.getValue());
                        gridTotal = gridTotal.add(item.getValue());
                        break;
                    case "2":
                        result.addToMap(mapEntry[1], item.getValue());
                        gridTotal = gridTotal.add(item.getValue());
                        break;
                    case "3":
                        result.addToMap(mapEntry[2], item.getValue());
                        gridTotal = gridTotal.add(item.getValue());
                        break;
                    case "4":
                        result.addToMap(mapEntry[3], item.getValue());
                        gridTotal = gridTotal.add(item.getValue());
                        break;
                    default:
                        result.addToMap(mapEntry[4], item.getValue());
                        gridTotal = gridTotal.add(item.getValue());
                }
            }
        }
        result.addToMap(mapEntry[5], gridTotal);
        // 返回查询结果.
        parent.put("GridStatistic", result.getMap());
        long t2 = System.currentTimeMillis();
        log.info("\n[ {} ][ 网格情况 ][ 网格数量统计 ]: 数据处理完成, 任务结束: 本步耗时 {} 毫秒, 总计耗时 {} 毫秒.", convert(t2), t2 - t1,
                t2 - t0);
        return CompletableFuture.completedFuture(parent);
    }

    /**
     * 获取网格人员信息
     * @param orgId 入参: 组织ID.
     * @return 统计结果.
     */
    @Async
    public CompletableFuture<?> gridPersonNumberAsyncStatistic(BigDecimal tenantId, BigDecimal orgId, JSONObject parent) {
        long t0 = System.currentTimeMillis();
        log.info("\n[ {} ][ 网格人员情况 ][ 网格人数统计 ]: 任务开始.", convert(t0));
        // 查询数据库, 获取原始数据
        List<KeyValuePair<BigDecimal>> list = gridDataStatisticMapper.statisticGridPerson(tenantId, orgId);
        long t1 = System.currentTimeMillis();
        log.info("\n[ {} ][ 网格人员情况 ][ 网格人数统计 ]: 原始数据查询成功: 本步耗时 {} 毫秒, 总计耗时 {} 毫秒.", convert(t1),t1 - t0,t1 - t0);

        // 初始化查询结果容器.
        // 初始化查询结果容器.管理类,科研类,生产经营类,项目建设类,生产作业类,网格人员总数
        String[] mapEntry = {"Manage", "Scientific", "ProductionOperation", "ProjectBuild","FlowHomework", "GridPersonTotal"};
        EChartsResult result = new EChartsResult();
        result.init(null, mapEntry, null);
        BigDecimal gridTotal = BigDecimal.ZERO;
        // 处理原始数据, 填充查询结果容器.
        for (KeyValuePair<BigDecimal> item : list) {
            if (Objects.nonNull(item.getKey())) {
                switch (item.getKey()) {
                    case "1":
                        result.addToMap(mapEntry[0], item.getValue());
                        gridTotal = gridTotal.add(item.getValue());
                        break;
                    case "2":
                        result.addToMap(mapEntry[1], item.getValue());
                        gridTotal = gridTotal.add(item.getValue());
                        break;
                    case "3":
                        result.addToMap(mapEntry[2], item.getValue());
                        gridTotal = gridTotal.add(item.getValue());
                        break;
                    case "4":
                        result.addToMap(mapEntry[3], item.getValue());
                        gridTotal = gridTotal.add(item.getValue());
                        break;
                    default:
                        result.addToMap(mapEntry[4], item.getValue());
                        gridTotal = gridTotal.add(item.getValue());
                }
            }
        }
        result.addToMap(mapEntry[5], gridTotal);
        // 返回查询结果.
        parent.put("GridPersonStatistic", result.getMap());
        long t2 = System.currentTimeMillis();
        log.info("\n[ {} ][ 网格人员情况 ][ 网格人数统计 ]: 数据处理完成, 任务结束: 本步耗时 {} 毫秒, 总计耗时 {} 毫秒.", convert(t2), t2 - t1,
                t2 - t0);
        return CompletableFuture.completedFuture(parent);
    }
}

Mapper层

package com.cnpc.dj.party.repository;


import com.cnpc.dj.party.common.KeyValuePair;
import org.apache.ibatis.annotations.Mapper;

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

@Mapper
public interface GridDataStatisticMapper {

    /**
     * 统计网格数量
     * @param tenantId
     * @param orgId
     * @return K V
     */
    List<KeyValuePair<BigDecimal>> statisticGrid(BigDecimal tenantId, BigDecimal orgId);

    /**
     * 统计网格人数
     * @param tenantId
     * @param orgId
     * @return K V
     */
    List<KeyValuePair<BigDecimal>> statisticGridPerson(BigDecimal tenantId, BigDecimal orgId);
}

 Mapper.xml层

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.cnpc.dj.party.repository.GridDataStatisticMapper">

    <resultMap id="KeyValuePair" type="com.cnpc.dj.party.common.KeyValuePair">
        <result column="K" property="key" jdbcType="VARCHAR" javaType="java.lang.String"/>
        <result column="V" property="value" jdbcType="INTEGER" javaType="java.math.BigDecimal"/>
    </resultMap>

    <select id="statisticGrid" parameterType="java.math.BigDecimal" resultMap="KeyValuePair">
        SELECT G.GRID_CLASS k,
               COUNT(*)     v
        FROM ZHONGHY_ONLINE_ANSWERS.DJ_GRID G
        WHERE G.IS_DELETE = '0'
         AND  G.ORG_CODE IN (SELECT o.ORG_CODE
                             FROM ZHONGHY_BASIC_INFO.DJ_ORG O
                             WHERE o.is_delete = '0'
                             AND o.is_del_org = '0'
                             AND o.tenant_id = #{tenantId, jdbcType=DECIMAL}
                             AND !REGEXP_LIKE(o.org_code, '^(000.001|000.002)')
        CONNECT BY PRIOR o.id = o.parent_id
        START WITH o.id = #{orgId, jdbcType=DECIMAL})
        GROUP BY G.GRID_CLASS
        ORDER BY G.GRID_CLASS
    </select>
    <select id="statisticGridPerson" parameterType="java.math.BigDecimal" resultMap="KeyValuePair">
        SELECT G.GRID_CLASS k,
               COUNT(*)     v
        FROM ZHONGHY_ONLINE_ANSWERS.DJ_GRID_RANGE R
        LEFT JOIN ZHONGHY_ONLINE_ANSWERS.DJ_GRID G
        ON R.GRID_ID = G.ID AND R.IS_DELETE = '0'
        WHERE G.IS_DELETE = '0'
          AND G.ORG_CODE IN (SELECT o.ORG_CODE
                             FROM ZHONGHY_BASIC_INFO.DJ_ORG O
                             WHERE o.is_delete = '0'
                               AND o.is_del_org = '0'
                               AND o.tenant_id = #{tenantId, jdbcType=DECIMAL}
                               AND !REGEXP_LIKE(o.org_code, '^(000.001|000.002)')
        CONNECT BY PRIOR o.id = o.parent_id
        START WITH o.id = #{orgId, jdbcType=DECIMAL})
        GROUP BY G.GRID_CLASS
        ORDER BY G.GRID_CLASS
    </select>
</mapper>

  公共类EChartsResult

package com.cnpc.dj.party.common;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.LinkedList;

/**
 * 陕西信合 - 数据统计.
 */
public class EChartsResult {
    public static final Comparator<? super Entry> VALUE_ASC = Comparator.comparing(Entry::getValue);
    public static final Comparator<? super Entry> VALUE_DESC = (Entry o1, Entry o2) -> o2.getValue()
                                                                                                       .compareTo(
                                                                                                               o1.getValue());
    private Comparator<? super Entry> comparator;
    private LinkedHashMap<String, Entry> entryMap;
    private LinkedHashMap<String, BigDecimal> valueMap;
    private BigDecimal total;

    public void init(String[] names, String[] keys, Comparator<? super Entry> comparator) {
        // 初始化EntryMap
        if (names != null && names.length > 0) {
            this.entryMap = new LinkedHashMap<>(names.length);
            for (String name : names) {
                this.entryMap.put(name, new Entry(name, BigDecimal.ZERO, null));
            }
        }
        // 初始化ValueMap
        if (keys != null && keys.length > 0) {
            this.valueMap = new LinkedHashMap<>(keys.length);
            for (String key : keys) {
                this.valueMap.put(key, BigDecimal.ZERO);
            }
        }
        // 设置Comparator
        this.comparator = comparator;
    }

    public void setComparator(Comparator<? super Entry> comparator) {
        this.comparator = comparator;
    }

    public void addToList(String name, BigDecimal value) {
        if (this.entryMap == null) {
            this.entryMap = new LinkedHashMap<>();
        }
        if (this.entryMap.containsKey(name)) {
            this.entryMap.get(name).addValue(value);
        } else {
            this.entryMap.put(name, new Entry(name, value, null));
        }
    }

    public void addToMap(String key, BigDecimal value) {
        if (this.valueMap == null) {
            this.valueMap = new LinkedHashMap<>();
        }
        this.valueMap.put(key, this.valueMap.containsKey(key)
                               ? this.valueMap.get(key).add(value)
                               : value);
    }

    public void calculate() {
        this.calculateTotal();
        this.calculatePercent();
    }

    public void calculate(BigDecimal total) {
        this.calculateTotal();
        this.calculatePercent(total);
    }

    private void calculateTotal() {
        if (this.entryMap != null) {
            // 初始化Total.
            this.total = BigDecimal.ZERO;
            // 累加求和.
            for (Entry entry : this.entryMap.values()) {
                this.total = this.total.add(entry.getValue());
            }
        }
    }

    private void calculatePercent() {
        if (this.entryMap != null) {
            // 若Total未初始化, 则先计算Total.
            if (this.total == null) {
                this.calculateTotal();
            }
            // 遍历EntryMap的所有项目, 计算百分比.
            this.entryMap.values().forEach(entry -> entry.calculatePercent(this.total));
        }
    }

    private void calculatePercent(BigDecimal total) {
        if (this.entryMap != null) {
            // 遍历EntryMap的所有项目, 计算百分比.
            this.entryMap.values().forEach(entry -> entry.calculatePercent(total));
        }
    }

    public void buildMap() {
        this.calculate();
        LinkedList<Entry> list = this.getList();
        if (list != null) {
            for (Entry entry : list) {
                this.addToMap(entry.getName(), entry.getValue());
                this.addToMap(entry.getName() + "Percent", entry.getPercent());
            }
            this.addToMap("Total", this.total);
        }
    }

    public LinkedList<Entry> getList() {
        if (this.entryMap != null) {
            LinkedList<Entry> list = new LinkedList<>(this.entryMap.values());
            if (this.comparator != null) {
                list.sort(this.comparator);
            }
            return list;
        }
        return null;
    }

    public LinkedHashMap<String, BigDecimal> getMap() {
        return this.valueMap;
    }

    public BigDecimal getTotal() {
        return this.total;
    }

    /**
     * ECharts 统计列表项.
     *
     * @author wangzijie05@cnpc.com.cn
     * @since 2019-03-15
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Entry {
        private String name;
        private BigDecimal value;
        private BigDecimal percent;

        void addValue(BigDecimal augend) {
            this.value = this.value.add(augend);
        }

        void calculatePercent(BigDecimal total) {
            if (BigDecimal.ZERO.equals(total)) {
                this.percent = BigDecimal.ZERO;
            } else {
                this.percent = this.value.abs().divide(total, 10, BigDecimal.ROUND_HALF_UP);
            }
        }
    }
}

 公共类KeyValuePair

package com.cnpc.dj.party.common;

import lombok.Data;

@Data
public class KeyValuePair<T> {

    private String key;

    private T value;

}

 postman测试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@百思不得奇解

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值