perf(仪表板): 优化echarts地图 增加世界地图

This commit is contained in:
fit2cloud-chenyw 2022-07-15 00:24:15 -04:00
parent 6b10b217db
commit adf6326732
6 changed files with 126 additions and 208 deletions

View File

@ -10,21 +10,13 @@ import java.util.List;
@RequestMapping("/api/map")
public interface MapApi {
@GetMapping("/resourceFull/{areaCode}")
String resourceFull(@PathVariable String areaCode);
@GetMapping("/asyncGeometry")
String asyncGeometry();
@GetMapping("/areaEntitys/{pcode}")
List<AreaEntity> areaEntitys(@PathVariable String pcode);
/**
* 由于api有限流机制
* 请求失败后 调用重试方法
* @param areaCode
*/
@GetMapping("/retry/{areaCode}")
void retry(@PathVariable String areaCode);
@GetMapping("/globalEntitys/{pcode}")
List<AreaEntity> globalEntitys(@PathVariable String pcode);
}

View File

@ -2,6 +2,9 @@ package io.dataease.map.dto.entity;
public class Constants {
public static final String COUNTRY_CODE = "国gb";
public static final String COUNTRY_NAME = "国name";
public static final String PROVINCE_CODE = "省gb";
public static final String PROVINCE_NAME = "省name";

View File

@ -15,28 +15,9 @@ import java.util.List;
@RestController
public class MapServer implements MapApi {
@Resource
private MapService mapService;
@Override
public String resourceFull(@PathVariable String areaCode) {
return mapService.geometry(areaCode);
}
@Override
public String asyncGeometry() {
try {
List<AreaEntity> areaEntities = mapService.areaEntities();
MapUtils.recursionWriteFull(areaEntities);
}catch (Exception e) {
LogUtil.error(e);
return e.getMessage();
}
return "async success";
}
@Override
public List<AreaEntity> areaEntitys(@PathVariable String pcode) {
List<AreaEntity> areaEntities = mapService.areaEntities();
@ -47,11 +28,11 @@ public class MapServer implements MapApi {
}
@Override
public void retry(@PathVariable String areaCode) {
List<AreaEntity> areaEntities = mapService.areaEntities();
AreaEntity areaEntity = MapUtils.nodeByCode(areaEntities, areaCode);
List<AreaEntity> targets = new ArrayList<>();
targets.add(areaEntity);
MapUtils.recursionWriteFull(targets);
public List<AreaEntity> globalEntitys(String pcode) {
List<AreaEntity> areaEntities = mapService.globalEntities();
if (StringUtils.equals(pcode, "0")) {
return areaEntities;
}
return mapService.entitysByPid(areaEntities, pcode);
}
}

View File

@ -1,6 +1,5 @@
package io.dataease.map.service;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.file.FileReader;
import io.dataease.map.dto.entity.AreaEntity;
@ -14,22 +13,20 @@ import java.util.List;
@Service
public class MapService {
private static final String dirPath = "/opt/dataease/data/feature/";
// 要不要加缓存呢
public String geometry(String areaCode) {
String path = dirPath + "full/" + areaCode + "_full.json";
FileReader fileReader = new FileReader(path);
return fileReader.readString();
}
@Cacheable("sys_map_areas")
public List<AreaEntity> areaEntities() {
List<AreaEntity> areaEntities = MapUtils.readAreaEntity();
return areaEntities;
}
@Cacheable("sys_map_areas")
public List<AreaEntity> globalEntities() {
List<AreaEntity> areaEntities = MapUtils.readGlobalAreaEntity();
return areaEntities;
}
public List<AreaEntity> entitysByPid(List<AreaEntity> entities, String pid) {
for (int i = 0; i < entities.size(); i++) {
AreaEntity areaEntity = entities.get(i);
@ -39,7 +36,7 @@ public class MapService {
if (CollectionUtil.isNotEmpty(areaEntity.getChildren())) {
List<AreaEntity> areaEntities = entitysByPid(areaEntity.getChildren(), pid);
if (null != areaEntities){
if (null != areaEntities) {
return areaEntities;
}
}
@ -48,6 +45,4 @@ public class MapService {
}
}

View File

@ -1,17 +1,16 @@
package io.dataease.map.utils;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import io.dataease.map.dto.entity.AreaEntity;
import io.dataease.map.dto.entity.Constants;
import io.dataease.plugins.common.base.domain.AreaMapping;
import io.dataease.plugins.common.base.domain.AreaMappingExample;
import io.dataease.plugins.common.base.domain.AreaMappingGlobal;
import io.dataease.plugins.common.base.domain.AreaMappingGlobalExample;
import io.dataease.plugins.common.base.mapper.AreaMappingGlobalMapper;
import io.dataease.plugins.common.base.mapper.AreaMappingMapper;
import io.dataease.commons.utils.LogUtil;
import io.dataease.map.dto.entity.*;
import io.dataease.map.dto.entity.Properties;
import io.dataease.map.dto.response.MapResponse;
import io.dataease.map.dto.response.MapResultDto;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
@ -21,24 +20,33 @@ import java.util.stream.Collectors;
@Component
public class MapUtils {
private static AreaMappingMapper areaMappingMapper;
private static AreaMappingGlobalMapper areaMappingGlobalMapper;
@Autowired
public void setAreaMappingMapper(AreaMappingMapper areaMappingMapper) {
MapUtils.areaMappingMapper = areaMappingMapper;
}
private static final String path = "/opt/dataease/data/行政区划列表2020-03.xlsx";
private static final String featureDir = "/opt/dataease/data/feature/";
@Autowired
public void setAreaMappingGlobalMapper(AreaMappingGlobalMapper areaMappingGlobalMapper) {
MapUtils.areaMappingGlobalMapper = areaMappingGlobalMapper;
}
private static final String featureDir = "/opt/dataease/data/feature/";
public static String formatCode(String code) {
return code;
}
public static List<AreaMappingGlobal> readGlobalCodes() {
AreaMappingGlobalExample example = new AreaMappingGlobalExample();
List<AreaMappingGlobal> mappingGlobals = areaMappingGlobalMapper.selectByExample(example);
return mappingGlobals;
}
public static List<Map<String, Object>> readCodeList( ) {
public static List<Map<String, Object>> readCodeList() {
AreaMappingExample example = new AreaMappingExample();
List<AreaMapping> areaMappings = areaMappingMapper.selectByExample(example);
return areaMappings.stream().map(mapping -> {
@ -54,6 +62,74 @@ public class MapUtils {
}).collect(Collectors.toList());
}
public static List<AreaEntity> readGlobalAreaEntity() {
List<AreaMappingGlobal> maps = readGlobalCodes();
Map<String, AreaEntity> countryMap = new ConcurrentHashMap<>();
Map<String, AreaEntity> provinceMap = new ConcurrentHashMap<>();
Map<String, AreaEntity> cityMap = new ConcurrentHashMap<>();
Map<String, AreaEntity> countyMap = new ConcurrentHashMap<>();
AreaEntity globalRoot = globalRoot();
maps.stream().forEach(map -> {
String country_code = map.getCountryCode();
String province_code = map.getProvinceCode();
String city_code = map.getCityCode();
String county_code = map.getCountyCode();
// 是否是跨级直辖
Boolean isCrossLevel = StrUtil.equals(province_code, city_code)
&& !StrUtil.equals(province_code, "156710000");
if (!countryMap.containsKey(country_code)) {
String country_name = map.getCountryName();
AreaEntity child = AreaEntity.builder().code(country_code).name(country_name)
.pcode(globalRoot.getCode()).build();
countryMap.put(country_code, child);
globalRoot.addChild(child);
}
AreaEntity currentCountry = countryMap.get(country_code);
String province_name = map.getProvinceName();
if (!provinceMap.containsKey(province_code)) {
AreaEntity child = AreaEntity.builder().code(province_code).name(province_name)
.pcode(currentCountry.getCode()).build();
provinceMap.put(province_code, child);
currentCountry.addChild(child);
}
// 当前省
AreaEntity currentProvince = provinceMap.get(province_code);
String city_name = map.getCityName();
if (isCrossLevel) {
city_code = county_code;
city_name = map.getCountyName();
}
if (StringUtils.isNotBlank(city_code) && !cityMap.containsKey(city_code)) {
AreaEntity child = AreaEntity.builder().code(city_code).name(city_name).pcode(currentProvince.getCode())
.build();
cityMap.put(city_code, child);
currentProvince.addChild(child);
}
if (StringUtils.isNotBlank(county_code) && !isCrossLevel) {
// 当前市
AreaEntity currentCity = cityMap.get(city_code);
if (!countyMap.containsKey(county_code)) {
String county_name = map.getCountyName();
AreaEntity child = AreaEntity.builder().code(county_code).name(county_name)
.pcode(currentCity.getCode())
.build();
countyMap.put(county_code, child);
currentCity.addChild(child);
}
}
});
List<AreaEntity> result = new ArrayList<>();
result.add(globalRoot);
return result;
}
public static List<AreaEntity> readAreaEntity() {
List<Map<String, Object>> maps = readCodeList();
@ -75,15 +151,15 @@ public class MapUtils {
// 是否是跨级直辖
Boolean isCrossLevel = StrUtil.equals(province_code, city_code) && !StrUtil.equals(province_code, "710000");
if (!provinceMap.containsKey(province_code)) {
String province_name = map.get(Constants.PROVINCE_NAME).toString();
AreaEntity child = AreaEntity.builder().code(province_code).name(province_name).pcode(china.getCode()).build();
AreaEntity child = AreaEntity.builder().code(province_code).name(province_name).pcode(china.getCode())
.build();
provinceMap.put(province_code, child);
china.addChild(child);
}
//当前省
// 当前省
AreaEntity currentProvince = provinceMap.get(province_code);
String city_name = map.get(Constants.CITY_NAME).toString();
@ -92,16 +168,19 @@ public class MapUtils {
city_name = map.get(Constants.COUNTY_NAME).toString();
}
if (!cityMap.containsKey(city_code)) {
AreaEntity child = AreaEntity.builder().code(city_code).name(city_name).pcode(currentProvince.getCode()).build();
AreaEntity child = AreaEntity.builder().code(city_code).name(city_name).pcode(currentProvince.getCode())
.build();
cityMap.put(city_code, child);
currentProvince.addChild(child);
}
if (!isCrossLevel) {
//当前市
// 当前市
AreaEntity currentCity = cityMap.get(city_code);
if (!countyMap.containsKey(county_code)) {
String county_name = map.get(Constants.COUNTY_NAME).toString();
AreaEntity child = AreaEntity.builder().code(county_code).name(county_name).pcode(currentCity.getCode()).build();
AreaEntity child = AreaEntity.builder().code(county_code).name(county_name)
.pcode(currentCity.getCode())
.build();
countyMap.put(county_code, child);
currentCity.addChild(child);
}
@ -116,148 +195,8 @@ public class MapUtils {
return AreaEntity.builder().code("100000").name("中华人民共和国").build();
}
public static void recursionWrite(List<AreaEntity> areaEntityList) {
areaEntityList.forEach(areaEntity -> {
String code = areaEntity.getCode();
MapResponse mapResponse = HttpUtils.get(code);
if (StrUtil.equals("1", mapResponse.getStatus()) && StrUtil.equalsAnyIgnoreCase("ok", mapResponse.getInfo()) && StrUtil.equalsAnyIgnoreCase("10000", mapResponse.getInfocode())) {
List<District> districts = mapResponse.getDistricts();
if (CollectionUtil.isNotEmpty(districts)) {
List<Feature> kidFeatures = districts.stream().map(district -> buildFeature(district, areaEntity)).collect(Collectors.toList());
MapResultDto mapResultDto = buildGeometry(kidFeatures);
writeFeatureFile(mapResultDto, areaEntity.getCode());
private static AreaEntity globalRoot() {
return AreaEntity.builder().code("000000000").name("地球村").build();
}
}
if (CollectionUtil.isNotEmpty(areaEntity.getChildren())) {
recursionWrite(areaEntity.getChildren());
}
});
}
public static void recursionWriteFull(List<AreaEntity> areaEntityList) {
areaEntityList.forEach(areaEntity -> {
List<AreaEntity> childrens = areaEntity.getChildren();
if (CollectionUtil.isEmpty(childrens)) {
childrens = new ArrayList<>();
childrens.add(areaEntity);
}
List<Feature> features = new ArrayList<>();
childrens.stream().forEach(child -> {
MapResponse mapResponse = HttpUtils.get(child.getCode());
if (StrUtil.equals("1", mapResponse.getStatus()) && StrUtil.equalsAnyIgnoreCase("ok", mapResponse.getInfo()) && StrUtil.equalsAnyIgnoreCase("10000", mapResponse.getInfocode())) {
List<District> districts = mapResponse.getDistricts();
if (CollectionUtil.isNotEmpty(districts)) {
List<Feature> kidFeatures = districts.stream().map(district -> buildFeature(district, child)).collect(Collectors.toList());
features.addAll(kidFeatures);
}
}else {
LogUtil.error("请求节点错误 请手动补偿: " + areaEntity.getName() +" -> "+child.getName());
}
});
if (CollectionUtil.isNotEmpty(features)) {
MapResultDto mapResultDto = buildGeometry(features);
writeFeatureFileFull(mapResultDto, areaEntity.getCode() + "_full");
}
if (CollectionUtil.isNotEmpty(areaEntity.getChildren())) {
recursionWriteFull(areaEntity.getChildren());
}
});
}
public static Feature buildFeature(District district, AreaEntity areaEntity) {
String type = "Feature";
Properties properties = new Properties();
properties.setAdcode(district.getAdcode());
properties.setName(district.getName());
properties.setCenter(Arrays.stream(district.getCenter().split(",")).map(Double::parseDouble).collect(Collectors.toList()));
properties.setCentroid(properties.getCenter());
properties.setChildrenNum(CollectionUtil.isNotEmpty(areaEntity.getChildren()) ? areaEntity.getChildren().size() : 0);
properties.setLevel(district.getLevel());
Parent parent = new Parent();
parent.setAdcode(areaEntity.getPcode());
properties.setParent(parent);
String polylineStr = district.getPolyline();
String[] polylines = polylineStr.split("[|]");
List<List<List<List<Double>>>> multiPolygon = Arrays.stream(polylines).map(polyline -> {
String[] strings = polyline.split(";");
List<List<Double>> line = Arrays.stream(strings).map(str -> {
String[] pointstr = str.split(",");
List<String> strPoint = Arrays.asList(pointstr);
List<Double> point = strPoint.stream().map(Double::parseDouble).collect(Collectors.toList());
return point;
}).collect(Collectors.toList());
List<Double> firstPoint = line.get(0);
List<Double> lastPoint = line.get(line.size() - 1);
// 线的起始点和终点没有重合 说明没有闭合 需要手动闭合
if (firstPoint.get(0) != lastPoint.get(0) || firstPoint.get(1) != lastPoint.get(1)) {
line.add(firstPoint);
}
List<List<List<Double>>> polygon = new ArrayList<>();
polygon.add(line);
return polygon;
}).collect(Collectors.toList());
Geometry geometry = new Geometry();
geometry.setType("MultiPolygon");
geometry.setCoordinates(multiPolygon);
Feature feature = new Feature();
feature.setType(type);
feature.setProperties(properties);
feature.setGeometry(geometry);
return feature;
}
public static MapResultDto buildGeometry(List<Feature> features) {
MapResultDto mapResultDto = new MapResultDto();
mapResultDto.setType("FeatureCollection");
mapResultDto.setFeatures(features);
return mapResultDto;
}
public static void writeFeatureFile(MapResultDto mapResultDto, String fileName) {
String path = featureDir + fileName + ".json";
FileWriter fileWriter = new FileWriter(path);
String content = JSONUtil.toJsonStr(mapResultDto);
fileWriter.write(content);
}
public static void writeFeatureFileFull(MapResultDto mapResultDto, String fileName) {
String path = featureDir + "full/" + fileName + ".json";
FileWriter fileWriter = new FileWriter(path);
String content = JSONUtil.toJsonStr(mapResultDto);
fileWriter.write(content);
}
public static AreaEntity nodeByCode(List<AreaEntity> areaEntities, String code) {
for (int i = 0; i < areaEntities.size(); i++) {
AreaEntity areaEntity = areaEntities.get(i);
if (StrUtil.equals(areaEntity.getCode(), code)) {
return areaEntity;
}
if (CollectionUtil.isNotEmpty(areaEntity.getChildren())) {
AreaEntity temp = nodeByCode(areaEntity.getChildren(), code);
if (null != temp){
return temp;
}
}
}
return null;
}
}

View File

@ -8,6 +8,14 @@ export const areaMapping = () => {
})
}
export const globalMapping = () => {
return request({
url: '/api/map/globalEntitys/0',
method: 'get',
loading: true
})
}
export function geoJson(areaCode) {
return request({
url: '/geo/' + areaCode + '_full.json',