forked from github/dataease
perf(仪表板): 优化echarts地图 增加世界地图
This commit is contained in:
parent
6b10b217db
commit
adf6326732
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user