xieb
2024-06-19 408406dff8f428e1439dbf909bc4f5d317cdaf5b
Merge remote-tracking branch 'origin/jtdev' into jtdev
4 files modified
3 files added
264 ■■■■■ changed files
skjcmanager/skjcmanager-service/skjcmanager-sm/pom.xml 5 ●●●●● patch | view | raw | blame | history
skjcmanager/skjcmanager-service/skjcmanager-sm/src/main/java/cn/gistack/sm/sjztmd/constant/RainfallConstant.java 21 ●●●●● patch | view | raw | blame | history
skjcmanager/skjcmanager-service/skjcmanager-sm/src/main/java/cn/gistack/sm/sjztmd/controller/AttResBaseController.java 29 ●●●●● patch | view | raw | blame | history
skjcmanager/skjcmanager-service/skjcmanager-sm/src/main/java/cn/gistack/sm/sjztmd/service/IAttResBaseService.java 4 ●●●● patch | view | raw | blame | history
skjcmanager/skjcmanager-service/skjcmanager-sm/src/main/java/cn/gistack/sm/sjztmd/service/impl/AttResBaseServiceImpl.java 148 ●●●●● patch | view | raw | blame | history
skjcmanager/skjcmanager-service/skjcmanager-sm/src/main/java/cn/gistack/sm/sjztmd/vo/AttResWithRainfall.java 14 ●●●●● patch | view | raw | blame | history
skjcmanager/skjcmanager-service/skjcmanager-sm/src/main/java/cn/gistack/sm/sjztmd/vo/RainfallGridData.java 43 ●●●●● patch | view | raw | blame | history
skjcmanager/skjcmanager-service/skjcmanager-sm/pom.xml
@@ -114,6 +114,11 @@
            <artifactId>im4java</artifactId>
            <version>1.4.0</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.25</version>
        </dependency>
    </dependencies>
    <build>
skjcmanager/skjcmanager-service/skjcmanager-sm/src/main/java/cn/gistack/sm/sjztmd/constant/RainfallConstant.java
New file
@@ -0,0 +1,21 @@
package cn.gistack.sm.sjztmd.constant;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
public class RainfallConstant {
    // 气象未来3天预报服务接口
    public static final String FORECAST_SERVICE_URL =
        "https://sk.hubeishuiyi.cn/sltqxyb/forecast/extraForecast/getSltRainGridForecastData/";
    public static final String REQUEST_JSON_BODY = "{\"dayIndex\":\"%s\"}";
    public static final String X_TOKEN = "2a1ded7e-85f2-4e42-a97a-5651d745f8e1";
    public static final int[] EMPTY_ATT_RES_NUM_ARRAY = IntStream.generate(() -> 0).limit(8).toArray();
    public static final List<String> RAIN_FALL_RANGES = Arrays.asList("(250,+)", "(100,250]", "(50,100]", "(25,50]"
            , "(10,25]", "(5,10]", "(0.1,5]", "[0,0.1]");
}
skjcmanager/skjcmanager-service/skjcmanager-sm/src/main/java/cn/gistack/sm/sjztmd/controller/AttResBaseController.java
@@ -9,6 +9,7 @@
import cn.gistack.sm.sjztmd.service.IAttResBaseService;
import cn.gistack.sm.sjztmd.vo.AttAdBaseVO;
import cn.gistack.sm.sjztmd.vo.AttResBaseVO;
import cn.gistack.sm.sjztmd.vo.AttResWithRainfall;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
@@ -26,6 +27,7 @@
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;
import io.swagger.annotations.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@@ -133,4 +135,31 @@
        return R.status(attResBaseService.updateIsShowStatus(ids,status));
    }
    /**
     * 根据预报降雨等值面图,识别出雨量范围内的水库清单
     * @param minRainfall 最小降雨量
     * @param maxRainfall 最大降雨量
     * @param dayIndex 预报的时段,0-2代表未来3天
     * @return 水库对象列表
     */
    @ApiOperation(value = "根据预报降雨等值面图,识别出雨量范围内的水库清单", notes = "根据预报降雨等值面图,识别出雨量范围内的水库清单")
    @PostMapping(value = "/getAttResByRainfall")
    public R<List<AttResWithRainfall>> getAttResByRainfall(
            @ApiParam(value = "最小降雨量") @RequestParam String minRainfall,
            @ApiParam(value = "最大降雨量") @RequestParam String maxRainfall,
            @ApiParam(value = "预报的时段,0-2代表未来3天") @RequestParam String dayIndex) {
        return R.data(attResBaseService.getAttResByRainfall(minRainfall, maxRainfall, dayIndex));
    }
    /**
     * 统计不同日降水量范围下的站点个数
     * @param dayIndex 预报的时段,0-2代表未来3天
     * @return 站点个数列表
     */
    @ApiOperation(value = "统计不同日降水量范围的站点个数", notes = "统计不同日降水量范围的站点个数")
    @PostMapping(value = "/getAttResNumByRainfall")
    public R<int[]> getAttResNumByRainfall(@ApiParam(value = "预报的时段,0-2代表未来3天") @RequestParam String dayIndex) {
        return R.data(attResBaseService.getAttResNumByRainfall(dayIndex));
    }
}
skjcmanager/skjcmanager-service/skjcmanager-sm/src/main/java/cn/gistack/sm/sjztmd/service/IAttResBaseService.java
@@ -75,4 +75,8 @@
    AttAdBase getYwxtResInfo(String cityName, String countyName);
    List<AttResBaseUserExcel> exportAttResBaseUser(Map<String, Object> params);
    List<AttResWithRainfall> getAttResByRainfall(String minRainfall, String maxRainfall, String dayIndex) ;
    int[] getAttResNumByRainfall(String dayIndex);
}
skjcmanager/skjcmanager-service/skjcmanager-sm/src/main/java/cn/gistack/sm/sjztmd/service/impl/AttResBaseServiceImpl.java
@@ -1,6 +1,7 @@
package cn.gistack.sm.sjztmd.service.impl;
import cn.gistack.sm.intelligentCall.mapper.CallTaskMapper;
import cn.gistack.sm.sjztmd.constant.RainfallConstant;
import cn.gistack.sm.sjztmd.dto.AttResBaseUserDTO;
import cn.gistack.sm.sjztmd.entity.AttAdBase;
import cn.gistack.sm.sjztmd.entity.AttResBase;
@@ -11,9 +12,20 @@
import cn.gistack.sm.sjztmd.service.IRelResLabelService;
import cn.gistack.sm.sjztmd.vo.*;
import cn.gistack.system.feign.ISysClient;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.utils.DateUtil;
@@ -23,6 +35,7 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.*;
import java.util.stream.Collectors;
/**
 * @ClassName AttResBaseServiceImpl
@@ -31,9 +44,12 @@
 * @Date 2023/4/21 20:01
 * @Version 1.0
 */
@Slf4j
@Service
@DS("zt")
public class AttResBaseServiceImpl extends ServiceImpl<AttResBaseMapper, AttResBase> implements IAttResBaseService {
    private static final ObjectMapper objectMapper = new ObjectMapper();
    @Autowired
    private CallTaskMapper callTaskMapper;
@@ -99,6 +115,138 @@
    }
    @Override
    public List<AttResWithRainfall> getAttResByRainfall(String minRainfall, String maxRainfall, String dayIndex) {
        if (StrUtil.isNotEmpty(dayIndex) && !Arrays.asList(0,1,2).contains(Integer.parseInt(dayIndex))) {
            throw new ServiceException("无效的dayIndex");
        }
        Double minRainfallDouble = null;
        Double maxRainfallDouble = null;
        if (StrUtil.isNotEmpty(minRainfall)) {
            minRainfallDouble = Double.parseDouble(minRainfall);
        }
        if (StrUtil.isNotEmpty(minRainfall)) {
            maxRainfallDouble = Double.parseDouble(maxRainfall);
        }
        // 调用气象预报服务接口
        String resJsonNodeStr;
        try (HttpResponse httpResponse = HttpRequest.post(RainfallConstant.FORECAST_SERVICE_URL)
            .header("Content-Type", "application/json")
            .header("X-token", RainfallConstant.X_TOKEN)
            .contentType("application/json")
            .body(String.format(RainfallConstant.REQUEST_JSON_BODY, StrUtil.isEmpty(dayIndex) ? "0" : dayIndex)).execute()) {
            JsonNode resJsonNode = objectMapper.readTree(httpResponse.body());
            resJsonNodeStr = resJsonNode.toString();
        } catch (Exception e) {
            throw new ServiceException("调用气象预报服务接口失败,详情:" + e.getMessage());
        }
        RainfallGridData gridData;
        try {
            gridData = objectMapper.readValue(resJsonNodeStr, RainfallGridData.class);
        } catch (JsonProcessingException e) {
            throw new ServiceException("转换降雨栅格数据失败,详情:" + e.getMessage());
        }
        RainfallGridData.Data data = gridData.getData();
        RainfallGridData.GridInfo gridInfo = data.getGridInfo();
        List<List<Double>> gridDataList = data.getGridData();
        if (gridDataList == null || gridDataList.isEmpty()) {
            log.warn("gridDataList为空!");
            return new ArrayList<>();
        }
        // 获取网格信息
        int lonNum = gridInfo.getLonNum();    // 网格横向(经度)
        double lonMax = gridInfo.getLonMax();
        double lonSpan = gridInfo.getLonSpan();  // 每个网格单元的经度跨度
        double latSpan = gridInfo.getLatSpan();   // 每个网格单元的纬度跨度
        double latMin = gridInfo.getLatMin();    // 网格的最小纬度
        double lonMin = gridInfo.getLonMin();   // 网格的最小经度
        double latMax = gridInfo.getLatMax();
        int latNum = gridInfo.getLatNum();    // 网格纵向(纬度)
        // 将网格数据转换为二维数组
        double[][] grid = new double[latNum][lonNum];
        for (int i = 0; i < latNum; i++) {
            List<Double> row = gridDataList.get(i);
            for (int j = 0; j < lonNum; j++) {
                grid[i][j] = row.get(j);
            }
        }
        LambdaQueryWrapper<AttResBase> queryWrapper = Wrappers.<AttResBase>query().lambda();
        List<AttResBase> attResBases = baseMapper.selectList(queryWrapper);
        List<AttResWithRainfall> attResWithRainfallList = new ArrayList<>();
        for (AttResBase attResBase : attResBases) {
            // 横向索引(lonIndex):(站点的经度 - 网格最小经度) / 每个网格单元的经度跨度
            int lonIndex = (int) ((Double.parseDouble(attResBase.getCenterLong()) - lonMin) / lonSpan);
            //  纵向索引(latIndex):(站点的纬度 - 网格最小纬度) / 每个网格单元的纬度跨度
            int latIndex = (int) ((Double.parseDouble(attResBase.getCenterLat()) - latMin) / latSpan);
            if (lonIndex >= 0 && lonIndex < lonNum && latIndex >= 0 && latIndex < latNum) {
                double rainfall = grid[latIndex][lonIndex];
                // 降雨量 <= 最小值的站点,都过滤掉, 降雨量为0除外
                if (null != minRainfallDouble &&  rainfall != 0 && rainfall <= minRainfallDouble) {
                    continue;
                }
                // 降雨量 > 最大值的站点,都过滤掉
                if (null != maxRainfallDouble &&  rainfall > maxRainfallDouble) {
                    continue;
                }
                AttResWithRainfall attResWithRainfall = new AttResWithRainfall();
                BeanUtil.copyProperties(attResBase, attResWithRainfall);
                attResWithRainfall.setRainfall(String.valueOf(rainfall));
                attResWithRainfallList.add(attResWithRainfall);
            } else {
                log.warn("AttRes {} is out of the grid range. centerLong: {}, centerLat: {}", attResBase.getName(),
                        attResBase.getCenterLong(), attResBase.getCenterLat());
            }
        }
        return attResWithRainfallList;
    }
    @Override
    public int[] getAttResNumByRainfall(String dayIndex) {
        List<AttResWithRainfall> attResByRainfall;
        // 获取站点降雨量失败或者返回站点列表为空时,直接返回空数组
        try {
            attResByRainfall = getAttResByRainfall(null, null, dayIndex);
        } catch (Exception e) {
            return RainfallConstant.EMPTY_ATT_RES_NUM_ARRAY;
        }
        if (attResByRainfall == null || attResByRainfall.isEmpty()) {
            return RainfallConstant.EMPTY_ATT_RES_NUM_ARRAY;
        }
        // 降雨范围-站点数量
        Map<String, Integer> rainfallRangeAttResNumMap = attResByRainfall.stream()
            .collect(Collectors.groupingBy(attResWithRainfall -> {
                int rainfall = Integer.parseInt(attResWithRainfall.getRainfall());
                if (rainfall > 250) {
                    return "(250,+)";
                } else if (rainfall > 100) {
                    return "(100,250]";
                } else if (rainfall > 50) {
                    return "(50,100]";
                } else if (rainfall > 25) {
                    return "(25,50]";
                } else if (rainfall > 10) {
                    return "(10,25]";
                } else if (rainfall > 5) {
                    return "(5,10]";
                } else if (rainfall > 0.1) {
                    return "(0.1,5]";
                } else if (rainfall >= 0) {
                    return "[0,0.1]";
                } else {
                    throw new ServiceException("无效的降雨值:" + rainfall);
                }
            }, Collectors.collectingAndThen(Collectors.counting(), Long::intValue)));
        int[] attResNumArray = new int[RainfallConstant.RAIN_FALL_RANGES.size()];
        for (int i = 0; i < RainfallConstant.RAIN_FALL_RANGES.size(); i++) {
            String range = RainfallConstant.RAIN_FALL_RANGES.get(i);
            attResNumArray[i] = rainfallRangeAttResNumMap.getOrDefault(range, 0);
        }
        return attResNumArray;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateResBaseByGuid(AttResBase attResBase) {
        attResBase.setUpdateTime(DateUtil.now());
skjcmanager/skjcmanager-service/skjcmanager-sm/src/main/java/cn/gistack/sm/sjztmd/vo/AttResWithRainfall.java
New file
@@ -0,0 +1,14 @@
package cn.gistack.sm.sjztmd.vo;
import cn.gistack.sm.sjztmd.entity.AttResBase;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class AttResWithRainfall extends AttResBase {
    @ApiModelProperty(value = "降雨量")
    private String rainfall;
}
skjcmanager/skjcmanager-service/skjcmanager-sm/src/main/java/cn/gistack/sm/sjztmd/vo/RainfallGridData.java
New file
@@ -0,0 +1,43 @@
package cn.gistack.sm.sjztmd.vo;
import lombok.Data;
import java.util.List;
@Data
public class RainfallGridData {
    private String code;
    private String msg;
    private Data data;
    @lombok.Data
    public static class Data {
        private String fileName;
        private GridInfo gridInfo;
        private List<List<Double>> gridData;
    }
    @lombok.Data
    public static class GridInfo {
        private int lonNum;
        private double lonMax;
        private double lonSpan;
        private double latSpan;
        private double latMin;
        private double lonMin;
        private double latMax;
        private int latNum;
    }
}