├── Code ├── .gitignore ├── Build程序启动脚本.bat ├── build.gradle.kts ├── db.7z ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── lib │ ├── font │ │ ├── IcoMoon.ttf.zip │ │ ├── Zondicons.ttf.zip │ │ └── brands.ttf.zip │ ├── opencv │ │ ├── opencv-4.7.0-0.jar │ │ ├── opencv原版备份.7z.001 │ │ ├── opencv原版备份.7z.002 │ │ ├── opencv原版备份.7z.003 │ │ ├── opencv原版备份.7z.004 │ │ └── opencv原版备份.7z.005 │ └── ui │ │ ├── JTattoo-1.6.13.jar │ │ ├── flatlaf-3.0.jar │ │ └── flatlaf-intellij-themes-3.0.jar ├── settings.gradle.kts └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── jmd │ │ │ ├── Application.java │ │ │ ├── ApplicationInit.kt │ │ │ ├── ApplicationOutputStream.kt │ │ │ ├── ApplicationPort.kt │ │ │ ├── ApplicationSetting.kt │ │ │ ├── ApplicationStore.kt │ │ │ ├── ApplicationTheme.kt │ │ │ ├── ApplicationTray.kt │ │ │ ├── ProgressBeanPostProcessor.kt │ │ │ ├── async │ │ │ ├── pool │ │ │ │ ├── executor │ │ │ │ │ ├── TileCalculationExecutorPool.java │ │ │ │ │ ├── TileDownloadExecutorPool.java │ │ │ │ │ └── TileMergeExecutorPool.java │ │ │ │ └── scheduler │ │ │ │ │ ├── IntervalConfig.java │ │ │ │ │ ├── IntervalTaskSchedulerConfig.java │ │ │ │ │ └── IntervalTaskSchedulerPool.java │ │ │ └── task │ │ │ │ ├── executor │ │ │ │ ├── TileCalculationTask.java │ │ │ │ ├── TileDownloadTask.java │ │ │ │ ├── TileErrorDownloadTask.java │ │ │ │ ├── TileMergeTask.java │ │ │ │ └── inst │ │ │ │ │ └── TileDownloadExecInst.java │ │ │ │ └── scheduler │ │ │ │ ├── DownloadMonitoringInterval.java │ │ │ │ └── TileMergeMonitoringInterval.java │ │ │ ├── browser │ │ │ ├── core │ │ │ │ └── ChromiumEmbeddedCore.kt │ │ │ ├── handler │ │ │ │ └── MenuHandler.kt │ │ │ └── view │ │ │ │ └── BrowserViewContainer.kt │ │ │ ├── callback │ │ │ ├── CommonCallback.java │ │ │ ├── DownloadMonitoringCallback.java │ │ │ ├── JavaScriptExecutionCallback.java │ │ │ ├── LayerDownloadCallback.java │ │ │ ├── LogCallback.java │ │ │ ├── TileDownloadedCallback.java │ │ │ ├── TileMergeFirstFinishBack.java │ │ │ ├── TileMergeMonitoringCallback.java │ │ │ └── TileViewSubmitCallback.java │ │ │ ├── common │ │ │ ├── Setting.java │ │ │ ├── StaticVar.java │ │ │ └── WsSendTopic.java │ │ │ ├── db │ │ │ ├── dao │ │ │ │ ├── AreaDao.java │ │ │ │ ├── CityDao.java │ │ │ │ ├── DistrictDao.java │ │ │ │ ├── ProvinceDao.java │ │ │ │ └── mapper │ │ │ │ │ ├── AreaMapper.xml │ │ │ │ │ ├── CityMapper.xml │ │ │ │ │ ├── DistrictMapper.xml │ │ │ │ │ └── ProvinceMapper.xml │ │ │ └── service │ │ │ │ ├── AllDistrictService.java │ │ │ │ └── impl │ │ │ │ └── AllDistrictServiceImpl.java │ │ │ ├── http │ │ │ ├── HttpClient.java │ │ │ ├── HttpDownload.java │ │ │ ├── OkHttpConfiguration.java │ │ │ └── ProxySetting.java │ │ │ ├── inst │ │ │ └── DownloadAmountInstance.java │ │ │ ├── model │ │ │ ├── controller │ │ │ │ └── WebDownloadSubmitVo.java │ │ │ ├── district │ │ │ │ ├── Area.java │ │ │ │ ├── City.java │ │ │ │ ├── District.java │ │ │ │ ├── Province.java │ │ │ │ └── WebAPIResult.java │ │ │ ├── geo │ │ │ │ ├── Bound.java │ │ │ │ ├── CoordinateTypeEnum.java │ │ │ │ ├── LngLatPoint.java │ │ │ │ ├── MercatorPoint.java │ │ │ │ ├── PixelPoint.java │ │ │ │ ├── Polygon.java │ │ │ │ └── Tile.java │ │ │ ├── page │ │ │ │ └── PageTileUrlBack.java │ │ │ ├── result │ │ │ │ ├── BlockAsyncTaskResult.java │ │ │ │ ├── DownloadResult.java │ │ │ │ ├── ImageMergeAsyncTaskResult.java │ │ │ │ └── ProcessInitializationResult.java │ │ │ ├── task │ │ │ │ ├── ErrorTileEntity.java │ │ │ │ ├── MergeProgressEntity.java │ │ │ │ ├── TaskAllInfoEntity.java │ │ │ │ ├── TaskBlockDivide.java │ │ │ │ ├── TaskBlockEntity.java │ │ │ │ ├── TaskCreateEntity.java │ │ │ │ ├── TaskExecEntity.java │ │ │ │ ├── TaskInstEntity.java │ │ │ │ ├── TaskProgressEntity.java │ │ │ │ └── TaskStatusEnum.java │ │ │ ├── theme │ │ │ │ └── ThemeEntity.java │ │ │ └── tile │ │ │ │ └── TileViewParam.java │ │ │ ├── os │ │ │ ├── CPUMonitor.java │ │ │ └── RAMMonitor.java │ │ │ ├── rx │ │ │ ├── Topic.kt │ │ │ ├── callback │ │ │ │ ├── OnMessageCallback.java │ │ │ │ └── OnSubscribeCallback.java │ │ │ ├── client │ │ │ │ ├── InnerMqClient.java │ │ │ │ └── impl │ │ │ │ │ └── NormalInnerMqClient.java │ │ │ └── service │ │ │ │ └── InnerMqService.java │ │ │ ├── task │ │ │ ├── TaskExecFunc.java │ │ │ ├── TaskState.java │ │ │ ├── TaskStepFunc.java │ │ │ └── TileMergeMatWrap.java │ │ │ ├── ui │ │ │ ├── MainFrame.java │ │ │ ├── MainMenuBar.java │ │ │ ├── StartupWindow.java │ │ │ ├── common │ │ │ │ ├── AutoScalingIcon.kt │ │ │ │ ├── BrowserViewPanel.kt │ │ │ │ ├── CommonContainerPanel.kt │ │ │ │ ├── CommonDialog.kt │ │ │ │ ├── CommonSubFrame.kt │ │ │ │ ├── IconLabel.kt │ │ │ │ └── NoScalingIcon.kt │ │ │ ├── foating │ │ │ │ ├── FloatingContentPanel.java │ │ │ │ ├── FloatingMenu.java │ │ │ │ └── FloatingWindow.java │ │ │ ├── frame │ │ │ │ ├── control │ │ │ │ │ └── AddLayerFrame.java │ │ │ │ ├── download │ │ │ │ │ ├── config │ │ │ │ │ │ ├── DownloadConfigFrame.java │ │ │ │ │ │ └── panel │ │ │ │ │ │ │ ├── DownloadErrorHandlerPanel.java │ │ │ │ │ │ │ ├── DownloadOtherSettingPanel.java │ │ │ │ │ │ │ ├── DownloadPathSelectorPanel.java │ │ │ │ │ │ │ └── DownloadZoomSelectorPanel.java │ │ │ │ │ └── preview │ │ │ │ │ │ └── DownloadPreviewFrame.java │ │ │ │ └── info │ │ │ │ │ ├── AboutFrame.java │ │ │ │ │ ├── DonateFrame.java │ │ │ │ │ └── LicenseFrame.java │ │ │ └── tab │ │ │ │ ├── a_map │ │ │ │ ├── MapControlPanel.java │ │ │ │ └── panel │ │ │ │ │ ├── BottomInfoPanel.java │ │ │ │ │ ├── CustomLayerButtonPanel.java │ │ │ │ │ ├── DistrictSelectorPanel.java │ │ │ │ │ ├── DrawTypePanel.java │ │ │ │ │ ├── LayerSelectorPanel.java │ │ │ │ │ ├── MapControlBrowserPanel.java │ │ │ │ │ ├── MapControlButtonPanel.java │ │ │ │ │ └── StatusInfoPanel.java │ │ │ │ ├── b_download │ │ │ │ ├── DownloadTaskPanel.java │ │ │ │ └── panel │ │ │ │ │ ├── ResourceUsagePanel.java │ │ │ │ │ ├── TaskLogPanel.java │ │ │ │ │ ├── TaskProgressPanel.java │ │ │ │ │ ├── TaskStatusPanel.java │ │ │ │ │ ├── TileMergeProgressPanel.java │ │ │ │ │ └── cpu │ │ │ │ │ └── CPUPercentageLinePanel.java │ │ │ │ ├── c_tile │ │ │ │ ├── TileViewPanel.java │ │ │ │ └── panel │ │ │ │ │ ├── TileApiAddressPanel.java │ │ │ │ │ ├── TileImageTypePanel.java │ │ │ │ │ ├── TilePathSelectorPanel.java │ │ │ │ │ └── TileViewBrowserPanel.java │ │ │ │ └── d_syslog │ │ │ │ └── SystemLogPanel.java │ │ │ ├── util │ │ │ ├── CommonUtils.java │ │ │ ├── ConnectorUtils.java │ │ │ ├── FontUtils.java │ │ │ ├── GeoUtils.java │ │ │ ├── ImageUtils.java │ │ │ ├── MyFileUtils.java │ │ │ └── TaskUtils.java │ │ │ ├── web │ │ │ ├── common │ │ │ │ ├── Constants.java │ │ │ │ ├── RESTfulResult.java │ │ │ │ └── WsSendData.java │ │ │ ├── config │ │ │ │ └── WebMvcConfig.java │ │ │ ├── controller │ │ │ │ ├── InfoController.kt │ │ │ │ ├── TileController.kt │ │ │ │ └── WebSubmitController.kt │ │ │ ├── service │ │ │ │ ├── TileService.java │ │ │ │ ├── WebSubmitService.java │ │ │ │ └── impl │ │ │ │ │ ├── TileServiceImpl.java │ │ │ │ │ └── WebSubmitServiceImpl.java │ │ │ └── websocket │ │ │ │ ├── config │ │ │ │ ├── SpringWebSocketConfig.java │ │ │ │ └── SpringWebSocketHandlerInterceptor.java │ │ │ │ └── handler │ │ │ │ ├── MapWebSocketHandler.java │ │ │ │ └── base │ │ │ │ └── BaseWebSocketHandler.java │ │ │ └── z0test │ │ │ └── TestFunc.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── jmd │ └── ApplicationTests.java ├── LICENSE ├── Other └── image │ ├── frame │ ├── add-tile-frame.png │ ├── add-tile-setting.png │ ├── download-frame-1.png │ ├── download-frame-2.png │ ├── float-window-1.png │ ├── float-window-2.png │ ├── main-frame-1.png │ ├── main-frame-2.png │ ├── main-frame-3.png │ ├── proxy-1.png │ ├── proxy-2.png │ ├── theme-1.png │ ├── theme-2.png │ ├── theme-3.png │ ├── theme-4.png │ ├── theme-5.png │ ├── theme-6.png │ ├── theme-7.png │ ├── theme-8.png │ ├── tile-view-browser.png │ ├── tile-view-frame-1.png │ └── tile-view-setting.png │ ├── other │ ├── opencv.png │ ├── sqlite.png │ └── web.png │ └── tile │ ├── 163712_032f9f19_1403243.webp │ ├── 184433_266b9408_1403243.webp │ ├── 191831_0fe37c36_1403243.webp │ ├── 191841_58a9107e_1403243.webp │ ├── 192008_a3e72cda_1403243.webp │ ├── 194201_51cbcc76_1403243.webp │ ├── 200828_c79e7461_1403243.webp │ ├── 201358_ee4b9a82_1403243.webp │ ├── 201415_178ebde6_1403243.webp │ ├── 235757_070c3fc7_1403243.webp │ ├── AQGA19U6SF0O7TQJGZGR8Q.png │ ├── YL2S6HW.png │ └── ZWGLCVCLS2V57.png ├── README.md ├── Web ├── .browserslistrc ├── .editorconfig ├── .gitignore ├── angular.json ├── package.json ├── src │ ├── app │ │ ├── app-routing.module.ts │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── common │ │ │ └── common-var.ts │ │ ├── connection │ │ │ ├── onmassage │ │ │ │ ├── map-message.connection.ts │ │ │ │ └── map-message.processor.ts │ │ │ └── websocket │ │ │ │ ├── ReconnectableWebSocket.ts │ │ │ │ └── WebSocketConfigOption.ts │ │ ├── http │ │ │ ├── http-client.service.ts │ │ │ ├── http-interceptor.provider.ts │ │ │ ├── http-interceptor.service.ts │ │ │ ├── http-method.ts │ │ │ ├── http-params.entity.ts │ │ │ └── restful-result.type.ts │ │ ├── map │ │ │ ├── draw │ │ │ │ ├── map-draw.ts │ │ │ │ └── map-wrap.ts │ │ │ ├── entity │ │ │ │ ├── Point.ts │ │ │ │ ├── PointEN.ts │ │ │ │ └── PointENObj.ts │ │ │ ├── geo-util.ts │ │ │ ├── map-base-simple.ts │ │ │ ├── map-base.ts │ │ │ ├── map-config-option.ts │ │ │ ├── map-source.ts │ │ │ └── source │ │ │ │ ├── amap-source.ts │ │ │ │ ├── baidu-source.ts │ │ │ │ ├── bing-source.ts │ │ │ │ ├── google-source.ts │ │ │ │ ├── mapbox-source.ts │ │ │ │ ├── osm-source.ts │ │ │ │ ├── tencent-source.ts │ │ │ │ └── tian-source.ts │ │ ├── model │ │ │ └── add-layer.type.ts │ │ ├── rx │ │ │ └── inner-mq │ │ │ │ ├── client │ │ │ │ ├── impl │ │ │ │ │ ├── lo-inner-mq.client.ts │ │ │ │ │ └── normal-inner-mq.client.ts │ │ │ │ └── inner-mq.client.ts │ │ │ │ ├── service │ │ │ │ └── inner-mq.service.ts │ │ │ │ ├── topic.ts │ │ │ │ └── util │ │ │ │ └── random.ts │ │ ├── service │ │ │ ├── info.service.ts │ │ │ └── submit.service.ts │ │ ├── util │ │ │ └── common-util.ts │ │ └── view │ │ │ └── page │ │ │ ├── index.page-module.ts │ │ │ ├── index.page.html │ │ │ ├── index.page.scss │ │ │ ├── index.page.ts │ │ │ ├── map-control │ │ │ ├── dialog │ │ │ │ ├── key-input-dialog.component.html │ │ │ │ ├── key-input-dialog.component.scss │ │ │ │ └── key-input-dialog.component.ts │ │ │ ├── map-control.page-module.ts │ │ │ ├── map-control.page.html │ │ │ ├── map-control.page.scss │ │ │ └── map-control.page.ts │ │ │ └── tile-view │ │ │ ├── tile-view.page-module.ts │ │ │ ├── tile-view.page.html │ │ │ ├── tile-view.page.scss │ │ │ └── tile-view.page.ts │ ├── assets │ │ └── lib │ │ │ ├── element-resize-detector │ │ │ ├── element-resize-detector.js │ │ │ └── element-resize-detector.min.js │ │ │ ├── elm-pep │ │ │ └── elm-pep.js │ │ │ └── openlayers │ │ │ ├── mapbox-streets-v6-style.js │ │ │ ├── ol.css │ │ │ └── ol.js │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ └── styles.scss ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json └── 若README.md无法正常显示,将项目fork到自己下面即可正常查看 /Code/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | 39 | *.DS_Store 40 | context/ 41 | log/ 42 | setting/ 43 | native/ 44 | 45 | assets/ 46 | src/main/resources/web 47 | src/main/resources/db.sqlite3 -------------------------------------------------------------------------------- /Code/Build程序启动脚本.bat: -------------------------------------------------------------------------------- 1 | cd /d %~dp0 2 | %1 start "" mshta vbscript:createobject("shell.application").shellexecute("""%~0""","::",,"runas",1)(window.close)&exit 3 | 4 | @echo off 5 | 6 | set JAVA_HOME="./openjdk-14.0.1" 7 | set CLASSPATH=.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar; 8 | set PATH=%JAVA_HOME%\bin; 9 | 10 | start javaw -jar -Dfile.encoding=utf-8 ./bin/map-download-1.0.jar 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Code/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | group = "com.jmd" 4 | version = "1.0-SNAPSHOT" 5 | description = "地图下载器" 6 | java.sourceCompatibility = JavaVersion.VERSION_17 7 | 8 | repositories { 9 | mavenLocal() 10 | maven { 11 | url = uri("https://maven.aliyun.com/nexus/content/groups/public/") 12 | } 13 | mavenCentral() 14 | } 15 | 16 | plugins { 17 | java 18 | kotlin("jvm") version "1.8.22" 19 | kotlin("plugin.spring") version "1.8.22" 20 | kotlin("plugin.lombok") version "1.8.22" 21 | id("io.freefair.lombok") version "8.0.1" 22 | id("org.springframework.boot") version "3.1.1" 23 | id("io.spring.dependency-management") version "1.1.0" 24 | } 25 | 26 | dependencies { 27 | implementation("org.springframework.boot:spring-boot-starter") 28 | implementation("org.springframework.boot:spring-boot-starter-web") 29 | implementation("org.springframework.boot:spring-boot-starter-websocket") 30 | implementation("org.springframework.boot:spring-boot-starter-tomcat") 31 | implementation("org.springframework.boot:spring-boot-configuration-processor") 32 | implementation("org.springframework.boot:spring-boot-starter-jdbc") 33 | testImplementation("org.springframework.boot:spring-boot-starter-test") 34 | implementation("com.squareup.okhttp3:okhttp") 35 | implementation("io.reactivex.rxjava3:rxjava") 36 | implementation("org.xerial:sqlite-jdbc") 37 | implementation("org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.2") 38 | implementation("commons-io:commons-io:2.13.0") 39 | implementation("com.alibaba.fastjson2:fastjson2:2.0.33") 40 | implementation(files("lib/ui/flatlaf-3.0.jar")) 41 | implementation(files("lib/ui/flatlaf-intellij-themes-3.0.jar")) 42 | implementation(files("lib/ui/JTattoo-1.6.13.jar")) 43 | implementation(files("lib/opencv/opencv-4.7.0-0.jar")) 44 | } 45 | 46 | sourceSets { 47 | main { 48 | resources { 49 | srcDirs("src/main/java") 50 | } 51 | } 52 | } 53 | 54 | tasks.jar { 55 | enabled = true 56 | manifest { 57 | attributes(mapOf("Main-Class" to "com.jmd.Application")) 58 | } 59 | } 60 | 61 | tasks.withType() { 62 | options.encoding = "UTF-8" 63 | } 64 | 65 | tasks.withType() { 66 | options.encoding = "UTF-8" 67 | } 68 | 69 | tasks.withType { 70 | kotlinOptions { 71 | freeCompilerArgs = listOf("-Xjsr305=strict") 72 | jvmTarget = "17" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Code/db.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Code/db.7z -------------------------------------------------------------------------------- /Code/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Code/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Code/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /Code/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if %ERRORLEVEL% equ 0 goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if %ERRORLEVEL% equ 0 goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | set EXIT_CODE=%ERRORLEVEL% 84 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 85 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 86 | exit /b %EXIT_CODE% 87 | 88 | :mainEnd 89 | if "%OS%"=="Windows_NT" endlocal 90 | 91 | :omega 92 | -------------------------------------------------------------------------------- /Code/lib/font/IcoMoon.ttf.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Code/lib/font/IcoMoon.ttf.zip -------------------------------------------------------------------------------- /Code/lib/font/Zondicons.ttf.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Code/lib/font/Zondicons.ttf.zip -------------------------------------------------------------------------------- /Code/lib/font/brands.ttf.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Code/lib/font/brands.ttf.zip -------------------------------------------------------------------------------- /Code/lib/opencv/opencv-4.7.0-0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Code/lib/opencv/opencv-4.7.0-0.jar -------------------------------------------------------------------------------- /Code/lib/opencv/opencv原版备份.7z.001: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Code/lib/opencv/opencv原版备份.7z.001 -------------------------------------------------------------------------------- /Code/lib/opencv/opencv原版备份.7z.002: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Code/lib/opencv/opencv原版备份.7z.002 -------------------------------------------------------------------------------- /Code/lib/opencv/opencv原版备份.7z.003: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Code/lib/opencv/opencv原版备份.7z.003 -------------------------------------------------------------------------------- /Code/lib/opencv/opencv原版备份.7z.004: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Code/lib/opencv/opencv原版备份.7z.004 -------------------------------------------------------------------------------- /Code/lib/opencv/opencv原版备份.7z.005: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Code/lib/opencv/opencv原版备份.7z.005 -------------------------------------------------------------------------------- /Code/lib/ui/JTattoo-1.6.13.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Code/lib/ui/JTattoo-1.6.13.jar -------------------------------------------------------------------------------- /Code/lib/ui/flatlaf-3.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Code/lib/ui/flatlaf-3.0.jar -------------------------------------------------------------------------------- /Code/lib/ui/flatlaf-intellij-themes-3.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Code/lib/ui/flatlaf-intellij-themes-3.0.jar -------------------------------------------------------------------------------- /Code/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "map-download" 2 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ApplicationInit.kt: -------------------------------------------------------------------------------- 1 | package com.jmd 2 | 3 | import com.jmd.ui.MainFrame 4 | import com.jmd.ui.StartupWindow 5 | import com.jmd.z0test.TestFunc 6 | import org.springframework.beans.factory.annotation.Autowired 7 | import org.springframework.boot.ApplicationArguments 8 | import org.springframework.boot.ApplicationRunner 9 | import org.springframework.core.annotation.Order 10 | import org.springframework.stereotype.Component 11 | import java.io.IOException 12 | import javax.swing.SwingUtilities 13 | 14 | @Component 15 | @Order(1) 16 | class ApplicationInit : ApplicationRunner { 17 | 18 | @Autowired 19 | private lateinit var mainFrame: MainFrame 20 | 21 | @Autowired 22 | private lateinit var test: TestFunc 23 | 24 | @Throws(IOException::class) 25 | override fun run(args: ApplicationArguments) { 26 | SwingUtilities.invokeLater { 27 | mainFrame.isVisible = true 28 | StartupWindow.getInstance().close() 29 | } 30 | // new Thread(() -> test.run()).start(); 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ApplicationOutputStream.kt: -------------------------------------------------------------------------------- 1 | package com.jmd 2 | 3 | import java.io.IOException 4 | import java.io.OutputStream 5 | import javax.swing.JTextArea 6 | import javax.swing.SwingUtilities 7 | 8 | class ApplicationOutputStream(destination: JTextArea?) : OutputStream() { 9 | 10 | private val destination: JTextArea 11 | 12 | init { 13 | requireNotNull(destination) { "Destination is null" } 14 | this.destination = destination 15 | } 16 | 17 | @Throws(IOException::class) 18 | override fun write(buffer: ByteArray, offset: Int, length: Int) { 19 | val text = String(buffer, offset, length) 20 | SwingUtilities.invokeLater { 21 | destination.append(text) 22 | destination.caretPosition = destination.text.length 23 | } 24 | } 25 | 26 | @Throws(IOException::class) 27 | override fun write(b: Int) { 28 | write(byteArrayOf(b.toByte()), 0, 1) 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ApplicationPort.kt: -------------------------------------------------------------------------------- 1 | package com.jmd 2 | 3 | import com.jmd.util.ConnectorUtils 4 | import org.apache.catalina.connector.Connector 5 | import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer 6 | import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory 7 | import org.springframework.boot.web.server.WebServerFactoryCustomizer 8 | import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory 9 | import org.springframework.context.annotation.Configuration 10 | 11 | @Configuration 12 | class ApplicationPort : WebServerFactoryCustomizer { 13 | 14 | companion object { 15 | @JvmField 16 | var startPort = 0 17 | } 18 | 19 | override fun customize(factory: ConfigurableServletWebServerFactory) { 20 | (factory as TomcatServletWebServerFactory).addConnectorCustomizers(TomcatConnectorCustomizer { connector: Connector -> 21 | // 获取可用端口,指定端口范围,如果返回-1则范围内没有可用的,此时会使用80端口 22 | val port = ConnectorUtils.findAvailablePort(26737, 26787) 23 | try { 24 | if (port < 0) { 25 | throw Exception("no available port !") 26 | } else { 27 | startPort = port 28 | connector.port = port 29 | } 30 | } catch (e: Exception) { 31 | e.printStackTrace() 32 | } 33 | }) 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ApplicationSetting.kt: -------------------------------------------------------------------------------- 1 | package com.jmd 2 | 3 | import com.jmd.common.Setting 4 | import com.jmd.util.MyFileUtils 5 | import java.io.File 6 | 7 | object ApplicationSetting { 8 | 9 | private val path = File(System.getProperty("user.dir") + "/setting") 10 | private val file = File(System.getProperty("user.dir") + "/setting/ApplicationSetting") 11 | 12 | private var setting: Setting 13 | 14 | init { 15 | if (!path.exists() && !path.isFile) { 16 | path.mkdir() 17 | } 18 | if (!file.exists() && !file.isFile) { 19 | setting = createDefault() 20 | } else { 21 | setting = loadSettingFile() 22 | } 23 | } 24 | 25 | @JvmStatic 26 | fun getSetting(): Setting { 27 | return setting 28 | } 29 | 30 | @JvmStatic 31 | fun save() { 32 | try { 33 | MyFileUtils.saveObj2File(setting, file.absolutePath) 34 | } catch (e: Exception) { 35 | e.printStackTrace() 36 | } 37 | } 38 | 39 | @JvmStatic 40 | fun save(s: Setting) { 41 | setting = s 42 | try { 43 | MyFileUtils.saveObj2File(setting, file.absolutePath) 44 | } catch (e: Exception) { 45 | e.printStackTrace() 46 | } 47 | } 48 | 49 | private fun createDefault(): Setting { 50 | val s = Setting("default") 51 | try { 52 | MyFileUtils.saveObj2File(s, file.absolutePath) 53 | } catch (e: Exception) { 54 | e.printStackTrace() 55 | } 56 | return s 57 | } 58 | 59 | private fun loadSettingFile(): Setting { 60 | var s: Setting 61 | try { 62 | s = MyFileUtils.readFile2Obj(file) as Setting 63 | } catch (e: Exception) { 64 | s = createDefault() 65 | e.printStackTrace() 66 | } 67 | return s 68 | } 69 | 70 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ApplicationStore.kt: -------------------------------------------------------------------------------- 1 | package com.jmd 2 | 3 | import javax.swing.JFrame 4 | import javax.swing.JTextArea 5 | 6 | object ApplicationStore { 7 | 8 | @JvmField 9 | var commonParentFrame: JFrame? = null 10 | 11 | @JvmField 12 | var consoleTextArea = JTextArea() 13 | 14 | @JvmField 15 | var MAIN_FRAME_HEIGHT = 0 16 | 17 | @JvmField 18 | var MAIN_FRAME_WIDTH = 0 19 | 20 | @JvmField 21 | var MAIN_FRAME_LOCATION_X = 0 22 | 23 | @JvmField 24 | var MAIN_FRAME_LOCATION_Y = 0 25 | 26 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ApplicationTheme.kt: -------------------------------------------------------------------------------- 1 | package com.jmd 2 | 3 | import com.jmd.ApplicationSetting.save 4 | import com.jmd.rx.Topic 5 | import com.jmd.rx.service.InnerMqService 6 | import jakarta.annotation.PostConstruct 7 | import org.springframework.stereotype.Component 8 | import javax.swing.JOptionPane 9 | import javax.swing.SwingUtilities 10 | import javax.swing.UIManager 11 | 12 | @Component 13 | class ApplicationTheme { 14 | 15 | private val currentThemeType: Int = ApplicationSetting.getSetting().getThemeType() 16 | private val innerMqService = InnerMqService.getInstance() 17 | 18 | @PostConstruct 19 | private fun init() { 20 | try { 21 | subInnerMqMessage() 22 | } catch (e: Exception) { 23 | e.printStackTrace() 24 | } 25 | } 26 | 27 | @Throws(Exception::class) 28 | private fun subInnerMqMessage() { 29 | val client = innerMqService.createClient() 30 | client.sub(Topic.CHANGE_THEME) { res: HashMap -> 31 | change( 32 | res["name"] as String?, res["type"] as Int?, res["clazz"] as String? 33 | ) 34 | } 35 | } 36 | 37 | fun change(name: String?, type: Int?, clazz: String?) { 38 | // 保存配置 39 | ApplicationSetting.getSetting().themeName = name 40 | ApplicationSetting.getSetting().themeName = name 41 | ApplicationSetting.getSetting().themeType = type 42 | ApplicationSetting.getSetting().themeClazz = clazz 43 | save() 44 | // 更新窗口 45 | if (currentThemeType == type) { 46 | SwingUtilities.invokeLater { 47 | try { 48 | UIManager.setLookAndFeel(clazz) 49 | } catch (ex: Exception) { 50 | ex.printStackTrace() 51 | } 52 | innerMqService.pub(Topic.UPDATE_THEME_TEXT, name) 53 | innerMqService.pub(Topic.UPDATE_UI, true) 54 | } 55 | } else { 56 | JOptionPane.showMessageDialog(null, "切换不同组的主题,程序重启后生效") 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ApplicationTray.kt: -------------------------------------------------------------------------------- 1 | package com.jmd 2 | 3 | import com.jmd.common.StaticVar 4 | import com.jmd.rx.Topic 5 | import com.jmd.rx.service.InnerMqService 6 | import com.jmd.util.ImageUtils 7 | import java.awt.MenuItem 8 | import java.awt.PopupMenu 9 | import java.awt.SystemTray 10 | import java.awt.TrayIcon 11 | import java.awt.event.ActionEvent 12 | import java.awt.event.MouseAdapter 13 | import java.awt.event.MouseEvent 14 | 15 | object ApplicationTray { 16 | 17 | private val innerMqService = InnerMqService.getInstance() 18 | 19 | @JvmStatic 20 | fun addSystemTray() { 21 | try { 22 | val image = ImageUtils.getResourceImage("assets/icon/map.png") 23 | println(image) 24 | if (SystemTray.isSupported()) { 25 | val tray = SystemTray.getSystemTray() 26 | val popupMenu = PopupMenu() 27 | val openItem = MenuItem("show") 28 | openItem.font = StaticVar.FONT_SourceHanSansCNNormal_12 29 | openItem.addActionListener { e: ActionEvent? -> innerMqService.pub(Topic.MAIN_FRAME_SHOW, true) } 30 | val exitItem = MenuItem("exit") 31 | exitItem.font = StaticVar.FONT_SourceHanSansCNNormal_12 32 | exitItem.addActionListener { e: ActionEvent? -> Application.exit() } 33 | popupMenu.add(openItem) 34 | popupMenu.add(exitItem) 35 | val trayIcon = TrayIcon(image, "地图下载器", popupMenu) 36 | trayIcon.isImageAutoSize = true 37 | trayIcon.addMouseListener(object : MouseAdapter() { 38 | override fun mouseClicked(e: MouseEvent) { 39 | if (e.clickCount == 2) { 40 | innerMqService.pub(Topic.MAIN_FRAME_SHOW, true) 41 | } 42 | } 43 | }) 44 | tray.add(trayIcon) 45 | } 46 | } catch (e: Exception) { 47 | throw RuntimeException(e) 48 | } 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ProgressBeanPostProcessor.kt: -------------------------------------------------------------------------------- 1 | package com.jmd 2 | 3 | import com.jmd.model.result.ProcessInitializationResult 4 | import io.reactivex.rxjava3.core.Observable 5 | import io.reactivex.rxjava3.subjects.BehaviorSubject 6 | import io.reactivex.rxjava3.subjects.Subject 7 | import org.springframework.beans.BeansException 8 | import org.springframework.beans.factory.config.BeanPostProcessor 9 | import org.springframework.context.ApplicationListener 10 | import org.springframework.context.event.ContextRefreshedEvent 11 | import org.springframework.stereotype.Component 12 | import java.util.concurrent.atomic.AtomicInteger 13 | 14 | @Component 15 | class ProgressBeanPostProcessor : BeanPostProcessor, ApplicationListener { 16 | 17 | private val count = AtomicInteger(0) 18 | private val total = 232 19 | 20 | @Throws(BeansException::class) 21 | override fun postProcessAfterInitialization(bean: Any, beanName: String): Any? { 22 | count.incrementAndGet() 23 | val result = ProcessInitializationResult() 24 | result.perc = count.get() * 100 / total 25 | result.beanName = bean.javaClass.packageName + "." + bean.javaClass.simpleName 26 | beans.onNext(result) 27 | // println(count.get()) 28 | return bean 29 | } 30 | 31 | override fun onApplicationEvent(applicationEvent: ContextRefreshedEvent) { 32 | beans.onComplete() 33 | } 34 | 35 | companion object { 36 | private val beans: Subject = BehaviorSubject.create() 37 | 38 | @JvmStatic 39 | fun observe(): Observable { 40 | return beans 41 | } 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/async/pool/executor/TileCalculationExecutorPool.java: -------------------------------------------------------------------------------- 1 | package com.jmd.async.pool.executor; 2 | 3 | import java.util.concurrent.ThreadPoolExecutor; 4 | 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.core.task.TaskExecutor; 8 | import org.springframework.scheduling.annotation.EnableAsync; 9 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 10 | 11 | @Configuration 12 | @EnableAsync 13 | public class TileCalculationExecutorPool { 14 | 15 | @Bean("TileCalculationExecutorPool") 16 | public TaskExecutor taskExecutor() { 17 | int count = Runtime.getRuntime().availableProcessors(); 18 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 19 | // 设置核心线程数 20 | if (count <= 2) { 21 | executor.setCorePoolSize(1); 22 | } else if (count <= 4) { 23 | executor.setCorePoolSize(2); 24 | } else if (count <= 6) { 25 | executor.setCorePoolSize(4); 26 | } else if (count <= 8) { 27 | executor.setCorePoolSize(4); 28 | } else { 29 | executor.setCorePoolSize(count / 2); 30 | } 31 | // 设置最大线程数 32 | if (count <= 2) { 33 | executor.setMaxPoolSize(1); 34 | } else if (count <= 4) { 35 | executor.setMaxPoolSize(3); 36 | } else if (count <= 6) { 37 | executor.setMaxPoolSize(4); 38 | } else { 39 | executor.setMaxPoolSize(count - 2); 40 | } 41 | // 设置队列容量 42 | // executor.setQueueCapacity(200); 43 | // 设置线程活跃时间(秒) 44 | // executor.setKeepAliveSeconds(60); 45 | // 设置默认线程名称 46 | executor.setThreadNamePrefix("TileCalculationExecutorPool-"); 47 | // 设置拒绝策略 48 | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 49 | // 等待所有任务结束后再关闭线程池 50 | executor.setWaitForTasksToCompleteOnShutdown(true); 51 | return executor; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/async/pool/executor/TileDownloadExecutorPool.java: -------------------------------------------------------------------------------- 1 | package com.jmd.async.pool.executor; 2 | 3 | import java.util.concurrent.ThreadPoolExecutor; 4 | 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.core.task.TaskExecutor; 9 | import org.springframework.scheduling.annotation.EnableAsync; 10 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 11 | 12 | @Configuration 13 | @EnableAsync 14 | public class TileDownloadExecutorPool { 15 | 16 | @Value("${pool.thread.tile-download}") 17 | private int count; 18 | 19 | private ThreadPoolTaskExecutor executor; 20 | 21 | @Bean("TileDownloadExecutorPool") 22 | public TaskExecutor taskExecutor() { 23 | executor = new ThreadPoolTaskExecutor(); 24 | // 设置核心线程数 25 | executor.setCorePoolSize(count); 26 | // 设置最大线程数 27 | executor.setMaxPoolSize((int) (count * 2)); 28 | // 设置队列容量 29 | // executor.setQueueCapacity(200); 30 | // 设置线程活跃时间(秒) 31 | // executor.setKeepAliveSeconds(60); 32 | // 设置默认线程名称 33 | executor.setThreadNamePrefix("TileDownloadExecutorPool-"); 34 | // 设置拒绝策略 35 | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 36 | // 等待所有任务结束后再关闭线程池 37 | executor.setWaitForTasksToCompleteOnShutdown(true); 38 | return executor; 39 | } 40 | 41 | public int getActiveCount() { 42 | return executor.getActiveCount(); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/async/pool/executor/TileMergeExecutorPool.java: -------------------------------------------------------------------------------- 1 | package com.jmd.async.pool.executor; 2 | 3 | import java.util.concurrent.ThreadPoolExecutor; 4 | 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.core.task.TaskExecutor; 8 | import org.springframework.scheduling.annotation.EnableAsync; 9 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 10 | 11 | @Configuration 12 | @EnableAsync 13 | public class TileMergeExecutorPool { 14 | 15 | private ThreadPoolTaskExecutor executor; 16 | 17 | @Bean("TileMergeExecutorPool") 18 | public TaskExecutor taskExecutor() { 19 | int count = Runtime.getRuntime().availableProcessors(); 20 | executor = new ThreadPoolTaskExecutor(); 21 | // 设置核心线程数 22 | executor.setCorePoolSize(count); 23 | // 设置最大线程数 24 | executor.setMaxPoolSize(count); 25 | // 设置队列容量 26 | // executor.setQueueCapacity(200); 27 | // 设置线程活跃时间(秒) 28 | // executor.setKeepAliveSeconds(60); 29 | // 设置默认线程名称 30 | executor.setThreadNamePrefix("TileMergeExecutorPool-"); 31 | // 设置拒绝策略 32 | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 33 | // 等待所有任务结束后再关闭线程池 34 | executor.setWaitForTasksToCompleteOnShutdown(true); 35 | return executor; 36 | } 37 | 38 | public int getActiveCount() { 39 | return executor.getActiveCount(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/async/pool/scheduler/IntervalConfig.java: -------------------------------------------------------------------------------- 1 | package com.jmd.async.pool.scheduler; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Setter 7 | @Getter 8 | public class IntervalConfig { 9 | 10 | private int id; 11 | private Runnable task; 12 | private long mill; 13 | 14 | public IntervalConfig(int id, Runnable task, long mill) { 15 | this.id = id; 16 | this.task = task; 17 | this.mill = mill; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/async/pool/scheduler/IntervalTaskSchedulerConfig.java: -------------------------------------------------------------------------------- 1 | package com.jmd.async.pool.scheduler; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.scheduling.annotation.EnableAsync; 6 | import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; 7 | 8 | import java.util.concurrent.ThreadPoolExecutor; 9 | 10 | @Configuration 11 | @EnableAsync 12 | public class IntervalTaskSchedulerConfig { 13 | 14 | @Bean("IntervalTaskSchedulerPool") 15 | public ThreadPoolTaskScheduler taskScheduler() { 16 | ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); 17 | // 定义一个线程池大小 18 | scheduler.setPoolSize(10); 19 | // 线程池名的前缀 20 | scheduler.setThreadNamePrefix("IntervalTaskSchedulerPool-"); 21 | // 设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean 22 | scheduler.setWaitForTasksToCompleteOnShutdown(true); 23 | // 设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住 24 | scheduler.setAwaitTerminationSeconds(60); 25 | // 线程池对拒绝任务的处理策略,当线程池没有处理能力的时候,该策略会直接在 execute 26 | // 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务 27 | scheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 28 | return scheduler; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/async/pool/scheduler/IntervalTaskSchedulerPool.java: -------------------------------------------------------------------------------- 1 | package com.jmd.async.pool.scheduler; 2 | 3 | import java.time.Duration; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | import java.util.concurrent.ScheduledFuture; 7 | 8 | import com.jmd.rx.Topic; 9 | import com.jmd.rx.service.InnerMqService; 10 | import jakarta.annotation.PostConstruct; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.scheduling.annotation.Async; 13 | import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; 14 | import org.springframework.scheduling.support.CronTrigger; 15 | import org.springframework.scheduling.support.PeriodicTrigger; 16 | import org.springframework.stereotype.Component; 17 | 18 | @Component 19 | public class IntervalTaskSchedulerPool { 20 | 21 | private final Map> intervalMap = new HashMap<>(); 22 | private final InnerMqService innerMqService = InnerMqService.getInstance(); 23 | 24 | @Autowired 25 | private ThreadPoolTaskScheduler taskScheduler; 26 | 27 | @PostConstruct 28 | private void init() { 29 | try { 30 | this.subInnerMqMessage(); 31 | } catch (Exception e) { 32 | e.printStackTrace(); 33 | } 34 | } 35 | 36 | @Async("IntervalTaskSchedulerPool") 37 | public ScheduledFuture setInterval(Runnable task, int secInterval) { 38 | return taskScheduler.schedule(task, (arg0) -> { 39 | var corn = "*/" + secInterval + " * * * * ?"; 40 | return new CronTrigger(corn).nextExecution(arg0); 41 | }); 42 | } 43 | 44 | @Async("IntervalTaskSchedulerPool") 45 | public ScheduledFuture setInterval(Runnable task, long millInterval) { 46 | var periodicTrigger = new PeriodicTrigger(Duration.ofMillis(millInterval)); 47 | periodicTrigger.setFixedRate(true); 48 | periodicTrigger.setInitialDelay(Duration.ofMillis(millInterval)); 49 | return taskScheduler.schedule(task, periodicTrigger); 50 | } 51 | 52 | public boolean clearInterval(ScheduledFuture future) { 53 | return future.cancel(true); 54 | } 55 | 56 | private void subInnerMqMessage() throws Exception { 57 | var client = this.innerMqService.createClient(); 58 | client.sub(Topic.SET_INTERVAL, (config) -> { 59 | if (intervalMap.get(config.getId()) == null) { 60 | ScheduledFuture future = setInterval(config.getTask(), config.getMill()); 61 | intervalMap.put(config.getId(), future); 62 | } 63 | }); 64 | client.sub(Topic.CLEAR_INTERVAL, (id) -> { 65 | ScheduledFuture future = intervalMap.get(id); 66 | if (future != null) { 67 | clearInterval(future); 68 | intervalMap.remove(id); 69 | } 70 | }); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/async/task/executor/TileCalculationTask.java: -------------------------------------------------------------------------------- 1 | package com.jmd.async.task.executor; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.Future; 5 | 6 | import org.springframework.scheduling.annotation.Async; 7 | import org.springframework.scheduling.annotation.AsyncResult; 8 | import org.springframework.stereotype.Component; 9 | 10 | import com.jmd.model.geo.Polygon; 11 | import com.jmd.model.task.TaskBlockEntity; 12 | import com.jmd.util.GeoUtils; 13 | 14 | @Component 15 | public class TileCalculationTask { 16 | 17 | @Async("TileCalculationExecutorPool") 18 | public Future exec( 19 | int z, 20 | long x0, long x1, 21 | long y0, long y1, 22 | List polygons 23 | ) { 24 | var name = z + "-" + x0 + "-" + x1 + "-" + y0 + "-" + y1; 25 | long count = 0L; 26 | for (var x = x0; x <= x1; x++) { 27 | if (Thread.currentThread().isInterrupted()) { 28 | break; 29 | } 30 | for (var y = y0; y <= y1; y++) { 31 | if (Thread.currentThread().isInterrupted()) { 32 | break; 33 | } 34 | var tile = GeoUtils.getTile(z, x, y); 35 | for (var polygon : polygons) { 36 | if (Thread.currentThread().isInterrupted()) { 37 | break; 38 | } 39 | if (GeoUtils.isTileInPolygon(tile, polygon) || GeoUtils.isPolygonInTile(tile, polygon)) { 40 | count = count + 1; 41 | break; 42 | } 43 | } 44 | } 45 | } 46 | var block = new TaskBlockEntity(name, z, x0, x1, y0, y1, count, x0, y0, 0L); 47 | return new AsyncResult<>(block); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/async/task/executor/TileDownloadTask.java: -------------------------------------------------------------------------------- 1 | package com.jmd.async.task.executor; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | 5 | import com.jmd.async.task.executor.inst.TileDownloadExecInst; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.scheduling.annotation.Async; 9 | import org.springframework.stereotype.Component; 10 | 11 | import com.jmd.model.result.BlockAsyncTaskResult; 12 | import com.jmd.model.task.TaskExecEntity; 13 | import com.jmd.http.HttpDownload; 14 | 15 | @Component 16 | public class TileDownloadTask { 17 | 18 | @Value("${download.retry}") 19 | private int retry; 20 | 21 | @Autowired 22 | private HttpDownload download; 23 | 24 | @Async("TileDownloadExecutorPool") 25 | public CompletableFuture exec(TaskExecEntity execParam) { 26 | var inst = new TileDownloadExecInst(retry, download, execParam); 27 | var result = inst.start(); 28 | return CompletableFuture.completedFuture(result); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/async/task/executor/TileMergeTask.java: -------------------------------------------------------------------------------- 1 | package com.jmd.async.task.executor; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.Future; 5 | 6 | import com.jmd.util.MyFileUtils; 7 | import org.springframework.scheduling.annotation.Async; 8 | import org.springframework.scheduling.annotation.AsyncResult; 9 | import org.springframework.stereotype.Component; 10 | 11 | import com.jmd.common.StaticVar; 12 | import com.jmd.model.geo.Polygon; 13 | import com.jmd.model.result.ImageMergeAsyncTaskResult; 14 | import com.jmd.task.TileMergeMatWrap; 15 | import com.jmd.util.GeoUtils; 16 | import com.jmd.util.TaskUtils; 17 | 18 | @Component 19 | public class TileMergeTask { 20 | 21 | @Async("TileMergeExecutorPool") 22 | public Future exec( 23 | TileMergeMatWrap mat, 24 | int z, 25 | long topLeftX, long topLeftY, 26 | long xStart, long xEnd, 27 | long yStart, long yEnd, 28 | List polygons, 29 | int imgType, String savePath, String pathStyle, 30 | int divideXIndex, int divideYIndex 31 | ) { 32 | var result = new ImageMergeAsyncTaskResult(); 33 | result.setXStart(xStart); 34 | result.setXEnd(xEnd); 35 | result.setYStart(yStart); 36 | result.setYEnd(yEnd); 37 | result.setDivideXIndex(divideXIndex); 38 | result.setDivideYIndex(divideYIndex); 39 | for (var x = xStart; x <= xEnd; x++) { 40 | if (Thread.currentThread().isInterrupted()) { 41 | break; 42 | } 43 | for (var y = yStart; y <= yEnd; y++) { 44 | if (Thread.currentThread().isInterrupted()) { 45 | break; 46 | } 47 | var tile = GeoUtils.getTile(z, x, y); 48 | var positionX = StaticVar.TILE_WIDTH * (x - topLeftX); 49 | var positionY = StaticVar.TILE_HEIGHT * (y - topLeftY); 50 | var filePathAndName = savePath + TaskUtils.getFilePathName(pathStyle, imgType, z, x, y); 51 | var isInFlag = false; 52 | for (var polygon : polygons) { 53 | isInFlag = GeoUtils.isTileInPolygon(tile, polygon) || GeoUtils.isPolygonInTile(tile, polygon); 54 | if (isInFlag) { 55 | break; 56 | } 57 | } 58 | mat.mergeToMat(MyFileUtils.checkFilePath(filePathAndName), positionX, positionY, isInFlag); 59 | } 60 | } 61 | return new AsyncResult<>(result); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/async/task/scheduler/DownloadMonitoringInterval.java: -------------------------------------------------------------------------------- 1 | package com.jmd.async.task.scheduler; 2 | 3 | import com.jmd.callback.DownloadMonitoringCallback; 4 | import com.jmd.model.task.TaskAllInfoEntity; 5 | import com.jmd.model.task.TaskBlockEntity; 6 | import com.jmd.model.task.TaskInstEntity; 7 | import com.jmd.model.task.TaskProgressEntity; 8 | 9 | public class DownloadMonitoringInterval implements Runnable { 10 | 11 | private TaskAllInfoEntity taskAllInfo; 12 | private DownloadMonitoringCallback callBack; 13 | private long lastCount = 0; 14 | 15 | public DownloadMonitoringInterval(TaskAllInfoEntity taskAllInfo, DownloadMonitoringCallback callBack) { 16 | this.taskAllInfo = taskAllInfo; 17 | this.callBack = callBack; 18 | } 19 | 20 | @Override 21 | public void run() { 22 | var runCount = getRunCount(); 23 | double allCount = taskAllInfo.getAllRealCount(); 24 | double perc = (double) runCount / allCount; 25 | this.callBack.execute(new TaskProgressEntity(lastCount, runCount, perc)); 26 | this.lastCount = runCount; 27 | } 28 | 29 | private long getRunCount() { 30 | var count = 0L; 31 | for (TaskInstEntity inst : taskAllInfo.getEachLayerTask().values()) { 32 | for (TaskBlockEntity block : inst.getBlocks().values()) { 33 | count = count + block.getRunCount(); 34 | } 35 | } 36 | return count; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/async/task/scheduler/TileMergeMonitoringInterval.java: -------------------------------------------------------------------------------- 1 | package com.jmd.async.task.scheduler; 2 | 3 | import com.jmd.callback.TileMergeMonitoringCallback; 4 | import com.jmd.model.task.MergeProgressEntity; 5 | import com.jmd.task.TileMergeMatWrap; 6 | 7 | public class TileMergeMonitoringInterval implements Runnable { 8 | 9 | private TileMergeMatWrap mat; 10 | 11 | private TileMergeMonitoringCallback tileMergeMonitoringCallback; 12 | 13 | public TileMergeMonitoringInterval(TileMergeMatWrap mat, TileMergeMonitoringCallback tileMergeMonitoringCallback) { 14 | this.mat = mat; 15 | this.tileMergeMonitoringCallback = tileMergeMonitoringCallback; 16 | } 17 | 18 | @Override 19 | public void run() { 20 | MergeProgressEntity progress = new MergeProgressEntity(); 21 | progress.setAllPixel(mat.getAllPixel()); 22 | progress.setRunPixel(mat.getRunPixel()); 23 | if (mat.getAllPixel() == 0L) { 24 | progress.setPerc(0.0); 25 | } else { 26 | progress.setPerc((double) mat.getRunPixel() / (double) mat.getAllPixel()); 27 | } 28 | this.tileMergeMonitoringCallback.execute(progress); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/browser/core/ChromiumEmbeddedCore.kt: -------------------------------------------------------------------------------- 1 | package com.jmd.browser.core 2 | 3 | import com.jetbrains.cef.JCefAppConfig 4 | import com.jmd.ApplicationPort 5 | import com.jmd.browser.handler.MenuHandler 6 | import com.jmd.browser.view.BrowserViewContainer 7 | import com.jmd.util.MyFileUtils 8 | import org.cef.CefApp 9 | import org.cef.CefClient 10 | import org.cef.browser.CefBrowser 11 | import org.cef.browser.CefRendering 12 | 13 | class ChromiumEmbeddedCore { 14 | 15 | // 双重校验锁式(Double Check) 16 | companion object { 17 | val instance: ChromiumEmbeddedCore by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { 18 | ChromiumEmbeddedCore() 19 | } 20 | } 21 | // 等效方法 22 | // public class SingletonDemo { 23 | // private volatile static SingletonDemo instance; 24 | // private SingletonDemo() {} 25 | // public static SingletonDemo getInstance() { 26 | // if (instance == null) { 27 | // synchronized(SingletonDemo.class) { 28 | // if(instance==null) { 29 | // instance = new SingletonDemo(); 30 | // } 31 | // } 32 | // } 33 | // return instance; 34 | // } 35 | // } 36 | 37 | private val cefApp: CefApp 38 | 39 | val version: String get() = "Chromium Embedded Framework (CEF), ChromeVersion: ${cefApp.version.chromeVersion}" 40 | 41 | init { 42 | val args = JCefAppConfig.getInstance().appArgs 43 | val settings = JCefAppConfig.getInstance().cefSettings 44 | settings.cache_path = MyFileUtils.checkFilePath( 45 | "${System.getProperty("user.dir")}/context/jcef/data_${ApplicationPort.startPort}" 46 | ) 47 | // 获取CefApp实例 48 | CefApp.startup(args) 49 | cefApp = CefApp.getInstance(args, settings) 50 | } 51 | 52 | fun createClient(container: BrowserViewContainer?): CefClient { 53 | val cefClient = cefApp.createClient() 54 | cefClient.addContextMenuHandler(MenuHandler(container!!)) 55 | return cefClient 56 | } 57 | 58 | fun createBrowser(client: CefClient, url: String?): CefBrowser { 59 | return client.createBrowser(url, CefRendering.DEFAULT, true) 60 | } 61 | 62 | fun dispose() { 63 | cefApp.dispose() 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/browser/handler/MenuHandler.kt: -------------------------------------------------------------------------------- 1 | package com.jmd.browser.handler 2 | 3 | import com.jmd.browser.view.BrowserViewContainer 4 | import org.cef.browser.CefBrowser 5 | import org.cef.browser.CefFrame 6 | import org.cef.callback.CefContextMenuParams 7 | import org.cef.callback.CefMenuModel 8 | import org.cef.callback.CefMenuModel.MenuId 9 | import org.cef.handler.CefContextMenuHandlerAdapter 10 | 11 | class MenuHandler(private val container: BrowserViewContainer) : CefContextMenuHandlerAdapter() { 12 | 13 | companion object { 14 | private const val MENU_ID_DEV_TOOL = 1000001 15 | } 16 | 17 | override fun onBeforeContextMenu( 18 | browser: CefBrowser, 19 | frame: CefFrame, 20 | params: CefContextMenuParams, 21 | model: CefMenuModel 22 | ) { 23 | // 清除菜单项 24 | model.clear() 25 | // 剪切、复制、粘贴 26 | model.addItem(MenuId.MENU_ID_COPY, "复制") 27 | model.addItem(MenuId.MENU_ID_CUT, "剪切") 28 | model.addItem(MenuId.MENU_ID_PASTE, "粘贴") 29 | model.addSeparator() // 分割线 30 | model.addItem(MenuId.MENU_ID_BACK, "返回") 31 | model.setEnabled(MenuId.MENU_ID_BACK, browser.canGoBack()) 32 | model.addItem(MenuId.MENU_ID_FORWARD, "前进") 33 | model.setEnabled(MenuId.MENU_ID_FORWARD, browser.canGoForward()) 34 | model.addItem(MenuId.MENU_ID_RELOAD, "刷新") 35 | model.addSeparator() // 分割线 36 | model.addItem(MenuId.MENU_ID_VIEW_SOURCE, "查看源码") 37 | model.addItem(MENU_ID_DEV_TOOL, "开发者工具") 38 | //创建子菜单 39 | // CefMenuModel cmodel = model.addSubMenu(MENU_ID_INJECTION, "脚本注入"); 40 | // cmodel.addItem(MENU_ID_ADDTEXT, "添加一段文本"); 41 | } 42 | 43 | override fun onContextMenuCommand( 44 | browser: CefBrowser, 45 | frame: CefFrame, 46 | params: CefContextMenuParams, 47 | commandId: Int, 48 | eventFlags: Int 49 | ): Boolean { 50 | when (commandId) { 51 | MenuId.MENU_ID_RELOAD -> { 52 | browser.reload() 53 | return true 54 | } 55 | 56 | MENU_ID_DEV_TOOL -> { 57 | container.toggleDevTools() 58 | return true 59 | } 60 | } 61 | return false 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/browser/view/BrowserViewContainer.kt: -------------------------------------------------------------------------------- 1 | package com.jmd.browser.view 2 | 3 | interface BrowserViewContainer { 4 | 5 | fun toggleDevTools() 6 | 7 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/callback/CommonCallback.java: -------------------------------------------------------------------------------- 1 | package com.jmd.callback; 2 | 3 | public interface CommonCallback { 4 | 5 | void execute(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/callback/DownloadMonitoringCallback.java: -------------------------------------------------------------------------------- 1 | package com.jmd.callback; 2 | 3 | import com.jmd.model.task.TaskProgressEntity; 4 | 5 | public interface DownloadMonitoringCallback { 6 | 7 | void execute(TaskProgressEntity progress); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/callback/JavaScriptExecutionCallback.java: -------------------------------------------------------------------------------- 1 | package com.jmd.callback; 2 | 3 | public interface JavaScriptExecutionCallback { 4 | 5 | void execute(String callback); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/callback/LayerDownloadCallback.java: -------------------------------------------------------------------------------- 1 | package com.jmd.callback; 2 | 3 | public interface LayerDownloadCallback { 4 | 5 | void execute(int z); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/callback/LogCallback.java: -------------------------------------------------------------------------------- 1 | package com.jmd.callback; 2 | 3 | public interface LogCallback { 4 | 5 | void execute(String e); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/callback/TileDownloadedCallback.java: -------------------------------------------------------------------------------- 1 | package com.jmd.callback; 2 | 3 | public interface TileDownloadedCallback { 4 | 5 | void execute(int z, String name, long count, long xRun, long yRun, boolean success); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/callback/TileMergeFirstFinishBack.java: -------------------------------------------------------------------------------- 1 | package com.jmd.callback; 2 | 3 | public interface TileMergeFirstFinishBack { 4 | 5 | void execute(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/callback/TileMergeMonitoringCallback.java: -------------------------------------------------------------------------------- 1 | package com.jmd.callback; 2 | 3 | import com.jmd.model.task.MergeProgressEntity; 4 | 5 | public interface TileMergeMonitoringCallback { 6 | 7 | void execute(MergeProgressEntity progress); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/callback/TileViewSubmitCallback.java: -------------------------------------------------------------------------------- 1 | package com.jmd.callback; 2 | 3 | public interface TileViewSubmitCallback { 4 | 5 | void execute(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/common/Setting.java: -------------------------------------------------------------------------------- 1 | package com.jmd.common; 2 | 3 | import java.io.Serial; 4 | import java.io.Serializable; 5 | import java.util.ArrayList; 6 | 7 | import com.jmd.model.setting.AddedLayerSetting; 8 | import lombok.Data; 9 | 10 | @Data 11 | public class Setting implements Serializable { 12 | 13 | @Serial 14 | private static final long serialVersionUID = 2828730448277028688L; 15 | 16 | private Integer themeType; 17 | private String themeName; 18 | private String themeClazz; 19 | private Boolean floatingWindowShow; 20 | private String lastDirPath; 21 | private ArrayList addedLayers; 22 | 23 | public Setting() { 24 | 25 | } 26 | 27 | public Setting(String type) { 28 | switch (type) { 29 | case "default": 30 | this.themeType = 3; 31 | this.themeName = "Flatlaf IntelliJ"; 32 | this.themeClazz = "com.formdev.flatlaf.FlatIntelliJLaf"; 33 | this.floatingWindowShow = true; 34 | this.addedLayers = new ArrayList<>(); 35 | break; 36 | default: 37 | break; 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/common/WsSendTopic.java: -------------------------------------------------------------------------------- 1 | package com.jmd.common; 2 | 3 | public class WsSendTopic { 4 | 5 | public static String INIT_MAP_CONFIG = "initMapConfig"; 6 | public static String ZOOM_IN = "ZoomIn"; 7 | public static String ZOOM_OUT = "ZoomOut"; 8 | public static String PAN = "Pan"; 9 | public static String FIT_VIEW = "FitView"; 10 | public static String GRID_SWITCH = "GridSwitch"; 11 | public static String SWITCH_RESOURCE = "SwitchResource"; 12 | public static String SWITCH_ADDED_RESOURCE = "SwitchAddedResource"; 13 | public static String REMOVE_ADDED_RESOURCE = "RemoveAddedResource"; 14 | public static String SWITCH_DRAW_TYPE = "SwitchDrawType"; 15 | public static String OPEN_DRAW = "OpenDraw"; 16 | public static String DRAW_POLYGON_AND_POSITING = "DrawPolygonAndPositing"; 17 | public static String REMOVE_SHAPE = "RemoveShape"; 18 | public static String SUBMIT_BLOCK_DOWNLOAD = "SubmitBlockDownload"; 19 | public static String SUBMIT_WORLD_DOWNLOAD = "SubmitWorldDownload"; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/db/dao/AreaDao.java: -------------------------------------------------------------------------------- 1 | package com.jmd.db.dao; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | 5 | import com.jmd.model.district.Area; 6 | 7 | @Mapper 8 | public interface AreaDao { 9 | 10 | int insert(Area area); 11 | 12 | int isExist(String adcode); 13 | 14 | Area getByAdcode(String adcode); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/db/dao/CityDao.java: -------------------------------------------------------------------------------- 1 | package com.jmd.db.dao; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.ibatis.annotations.Mapper; 6 | 7 | import com.jmd.model.district.City; 8 | 9 | @Mapper 10 | public interface CityDao { 11 | 12 | List queryAll(); 13 | 14 | List queryByPadcode(String padcode); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/db/dao/DistrictDao.java: -------------------------------------------------------------------------------- 1 | package com.jmd.db.dao; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.ibatis.annotations.Mapper; 6 | 7 | import com.jmd.model.district.District; 8 | 9 | @Mapper 10 | public interface DistrictDao { 11 | 12 | int insert(District district); 13 | 14 | List queryAll(); 15 | 16 | District queryByAdcode(String adcode); 17 | 18 | List queryByPadcode(String padcode); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/db/dao/ProvinceDao.java: -------------------------------------------------------------------------------- 1 | package com.jmd.db.dao; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.ibatis.annotations.Mapper; 6 | 7 | import com.jmd.model.district.Province; 8 | 9 | @Mapper 10 | public interface ProvinceDao { 11 | 12 | List queryAll(); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/db/dao/mapper/AreaMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | INSERT INTO 13 | tb_area(adcode, polyline) 14 | VALUES (#{adcode}, #{polyline}) 15 | 16 | 17 | 21 | 22 | 26 | 27 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/db/dao/mapper/CityMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 21 | 22 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/db/dao/mapper/DistrictMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | INSERT INTO 16 | tb_district(name, center, citycode, adcode, padcode) 17 | VALUES (#{name}, #{center}, #{citycode}, #{adcode}, #{padcode}) 18 | 19 | 20 | 23 | 24 | 27 | 28 | 31 | 32 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/db/dao/mapper/ProvinceMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/db/service/AllDistrictService.java: -------------------------------------------------------------------------------- 1 | package com.jmd.db.service; 2 | 3 | import java.util.List; 4 | 5 | import com.jmd.model.district.Area; 6 | import com.jmd.model.district.City; 7 | import com.jmd.model.district.District; 8 | import com.jmd.model.district.Province; 9 | 10 | public interface AllDistrictService { 11 | 12 | List getAllProvinces(); 13 | 14 | List getCitysByProvinceAdcode(String adcode); 15 | 16 | List getDistrictsByCityAdcode(String adcode); 17 | 18 | Area getAreaByAdcode(String adcode); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/db/service/impl/AllDistrictServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.jmd.db.service.impl; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | import com.jmd.db.dao.AreaDao; 9 | import com.jmd.db.dao.CityDao; 10 | import com.jmd.db.dao.DistrictDao; 11 | import com.jmd.db.dao.ProvinceDao; 12 | import com.jmd.db.service.AllDistrictService; 13 | import com.jmd.model.district.Area; 14 | import com.jmd.model.district.City; 15 | import com.jmd.model.district.District; 16 | import com.jmd.model.district.Province; 17 | 18 | @Service 19 | public class AllDistrictServiceImpl implements AllDistrictService { 20 | 21 | @Autowired 22 | private ProvinceDao provinceDao; 23 | @Autowired 24 | private CityDao cityDao; 25 | @Autowired 26 | private DistrictDao districtDao; 27 | @Autowired 28 | private AreaDao areaDao; 29 | 30 | @Override 31 | public List getAllProvinces() { 32 | return provinceDao.queryAll(); 33 | } 34 | 35 | @Override 36 | public List getCitysByProvinceAdcode(String adcode) { 37 | return cityDao.queryByPadcode(adcode); 38 | } 39 | 40 | @Override 41 | public List getDistrictsByCityAdcode(String adcode) { 42 | return districtDao.queryByPadcode(adcode); 43 | } 44 | 45 | @Override 46 | public Area getAreaByAdcode(String adcode) { 47 | return areaDao.getByAdcode(adcode); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/http/HttpDownload.java: -------------------------------------------------------------------------------- 1 | package com.jmd.http; 2 | 3 | import java.io.IOException; 4 | 5 | import com.jmd.util.MyFileUtils; 6 | import com.jmd.util.ImageUtils; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Component; 9 | 10 | import com.jmd.model.result.DownloadResult; 11 | import com.jmd.inst.DownloadAmountInstance; 12 | 13 | @Component 14 | public class HttpDownload { 15 | 16 | @Autowired 17 | private HttpClient http; 18 | @Autowired 19 | private DownloadAmountInstance downloadAmountInstance; 20 | 21 | // 通过URL下载文件 22 | public DownloadResult downloadTile(String url, int imgType, String pathAndName, int retry) { 23 | pathAndName = MyFileUtils.checkFilePath(pathAndName); 24 | var result = new DownloadResult(); 25 | var success = false; 26 | var bytes = http.getFileBytes(url, HttpClient.HEADERS); 27 | if (null != bytes) { 28 | try { 29 | var fileLength = this.saveImage(imgType, bytes, pathAndName); 30 | if (fileLength >= 0) { 31 | downloadAmountInstance.add(fileLength); 32 | success = true; 33 | } 34 | } catch (IOException e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | if (success) { 39 | result.setSuccess(true); 40 | } else if (Thread.currentThread().isInterrupted()) { 41 | result.setSuccess(false); 42 | } else { 43 | retry = retry - 1; 44 | if (retry >= 0) { 45 | try { 46 | Thread.sleep(1000); 47 | } catch (InterruptedException e) { 48 | e.printStackTrace(); 49 | } 50 | return downloadTile(url, imgType, pathAndName, retry); 51 | } else { 52 | result.setSuccess(false); 53 | } 54 | } 55 | return result; 56 | } 57 | 58 | // 转码并保存图片 59 | private long saveImage(int imgType, byte[] imgData, String pathAndName) throws IOException { 60 | switch (imgType) { 61 | case 2, 3, 4 -> { 62 | return switch (imgType) { 63 | case 2 -> ImageUtils.saveImageToJPG(imgData, 0.2f, pathAndName); 64 | case 4 -> ImageUtils.saveImageToJPG(imgData, 0.9f, pathAndName); 65 | // 3 66 | default -> ImageUtils.saveImageToJPG(imgData, 0.6f, pathAndName); 67 | }; 68 | } 69 | default -> { 70 | // 0, 1 71 | return ImageUtils.saveImageByOpenCV(imgData, pathAndName); 72 | } 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/http/OkHttpConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.jmd.http; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import javax.net.ssl.SSLContext; 6 | import javax.net.ssl.SSLSocketFactory; 7 | import javax.net.ssl.TrustManager; 8 | import javax.net.ssl.X509TrustManager; 9 | 10 | import java.security.KeyManagementException; 11 | import java.security.NoSuchAlgorithmException; 12 | import java.security.SecureRandom; 13 | import java.security.cert.CertificateException; 14 | import java.security.cert.X509Certificate; 15 | 16 | import org.springframework.beans.factory.annotation.Value; 17 | import org.springframework.context.annotation.Bean; 18 | import org.springframework.context.annotation.Configuration; 19 | 20 | import okhttp3.OkHttpClient; 21 | import okhttp3.ConnectionPool; 22 | 23 | @Configuration 24 | public class OkHttpConfiguration { 25 | 26 | @Value("${okhttp.connect-timeout}") 27 | private Integer connectTimeout; 28 | 29 | @Value("${okhttp.read-timeout}") 30 | private Integer readTimeout; 31 | 32 | @Value("${okhttp.write-timeout}") 33 | private Integer writeTimeout; 34 | 35 | @Value("${okhttp.max-idle-connections}") 36 | private Integer maxIdleConnections; 37 | 38 | @Value("${okhttp.keep-alive-duration}") 39 | private Long keepAliveDuration; 40 | 41 | @Bean 42 | public OkHttpClient okHttpClient() { 43 | return new OkHttpClient.Builder().sslSocketFactory(sslSocketFactory(), x509TrustManager()) 44 | // 是否开启缓存 45 | .retryOnConnectionFailure(true).connectionPool(pool()).connectTimeout(connectTimeout, TimeUnit.SECONDS) 46 | .readTimeout(readTimeout, TimeUnit.SECONDS).writeTimeout(writeTimeout, TimeUnit.SECONDS) 47 | .hostnameVerifier((hostname, session) -> true) 48 | // // 设置代理 49 | // .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8888))) 50 | // // 拦截器 51 | // .addInterceptor() 52 | .build(); 53 | } 54 | 55 | @Bean 56 | public X509TrustManager x509TrustManager() { 57 | return new X509TrustManager() { 58 | @Override 59 | public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 60 | } 61 | 62 | @Override 63 | public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 64 | } 65 | 66 | @Override 67 | public X509Certificate[] getAcceptedIssuers() { 68 | return new X509Certificate[0]; 69 | } 70 | }; 71 | } 72 | 73 | @Bean 74 | public SSLSocketFactory sslSocketFactory() { 75 | try { 76 | // 信任任何链接 77 | SSLContext sslContext = SSLContext.getInstance("TLS"); 78 | sslContext.init(null, new TrustManager[] { x509TrustManager() }, new SecureRandom()); 79 | return sslContext.getSocketFactory(); 80 | } catch (NoSuchAlgorithmException | KeyManagementException e) { 81 | e.printStackTrace(); 82 | } 83 | return null; 84 | } 85 | 86 | @Bean 87 | public ConnectionPool pool() { 88 | return new ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.SECONDS); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/http/ProxySetting.java: -------------------------------------------------------------------------------- 1 | package com.jmd.http; 2 | 3 | public class ProxySetting { 4 | 5 | public static boolean enable = false; 6 | public static String hostname = "127.0.0.1"; 7 | public static int port = 7890; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/inst/DownloadAmountInstance.java: -------------------------------------------------------------------------------- 1 | package com.jmd.inst; 2 | 3 | import java.text.DecimalFormat; 4 | 5 | import org.springframework.context.annotation.Scope; 6 | import org.springframework.stereotype.Component; 7 | 8 | @Component 9 | @Scope("singleton") 10 | public class DownloadAmountInstance { 11 | 12 | private final DecimalFormat df1 = new DecimalFormat("#.#"); 13 | private final String[] s = { "B", "KB", "MB", "GB" }; 14 | private long lastAmount = 0L; 15 | private long currentAmount = 0L; 16 | 17 | public synchronized void add(long amount) { 18 | this.currentAmount += amount; 19 | } 20 | 21 | public void saveLast() { 22 | this.lastAmount = this.currentAmount; 23 | } 24 | 25 | public String getDiffValue() { 26 | long diff = this.currentAmount - this.lastAmount; 27 | double d = (double) diff; 28 | int i = 0; 29 | while (!(d < 1024.0)) { 30 | d = d / 1024.0; 31 | i++; 32 | } 33 | return df1.format(d) + s[i]; 34 | } 35 | 36 | public void reset() { 37 | this.lastAmount = 0; 38 | this.currentAmount = 0; 39 | } 40 | 41 | public long getLastAmount() { 42 | return lastAmount; 43 | } 44 | 45 | public long getCurrentAmount() { 46 | return currentAmount; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/controller/WebDownloadSubmitVo.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.controller; 2 | 3 | import java.util.List; 4 | 5 | import lombok.Data; 6 | 7 | @Data 8 | public class WebDownloadSubmitVo { 9 | 10 | private String tileName; 11 | private String mapType; 12 | private List tileUrl; 13 | private List> points; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/district/Area.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.district; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class Area { 7 | 8 | private Integer id; 9 | private String adcode; 10 | private String polyline; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/district/City.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.district; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class City { 7 | 8 | private Integer id; 9 | private String name; 10 | private String center; 11 | private String citycode; 12 | private String adcode; 13 | private String padcode; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/district/District.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.district; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class District { 7 | 8 | private Integer id; 9 | private String name; 10 | private String center; 11 | private String citycode; 12 | private String adcode; 13 | private String padcode; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/district/Province.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.district; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class Province { 7 | 8 | private Integer id; 9 | private String province; 10 | private String adcode; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/district/WebAPIResult.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.district; 2 | 3 | import java.util.List; 4 | 5 | import lombok.Data; 6 | 7 | @Data 8 | public class WebAPIResult { 9 | 10 | private String name; 11 | private String citycode; 12 | private String adcode; 13 | private String polyline; 14 | private String center; 15 | private List districts; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/geo/Bound.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.geo; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class Bound { 7 | 8 | private MercatorPoint topLeft; 9 | private MercatorPoint topRight; 10 | private MercatorPoint bottomLeft; 11 | private MercatorPoint bottomRight; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/geo/CoordinateTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.geo; 2 | 3 | public enum CoordinateTypeEnum { 4 | 5 | WGS84, GCJ02, BD09; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/geo/LngLatPoint.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.geo; 2 | 3 | import java.io.Serializable; 4 | 5 | import com.jmd.util.GeoUtils; 6 | 7 | import lombok.Data; 8 | 9 | @Data 10 | public class LngLatPoint implements Serializable { 11 | 12 | private static final long serialVersionUID = -3504030834818220866L; 13 | 14 | private Double lng; 15 | private Double lat; 16 | 17 | public LngLatPoint() { 18 | 19 | } 20 | 21 | public LngLatPoint(double lng, double lat) { 22 | this.lng = lng; 23 | this.lat = lat; 24 | } 25 | 26 | public MercatorPoint convert2Mercator() { 27 | return GeoUtils.LngLat2Mercator(this); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/geo/MercatorPoint.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.geo; 2 | 3 | import java.io.Serializable; 4 | 5 | import com.jmd.util.GeoUtils; 6 | 7 | import lombok.Data; 8 | 9 | @Data 10 | public class MercatorPoint implements Serializable { 11 | 12 | private static final long serialVersionUID = 4066123199303085477L; 13 | 14 | private Double lng; 15 | private Double lat; 16 | 17 | public MercatorPoint() { 18 | 19 | } 20 | 21 | public MercatorPoint(double lng, double lat) { 22 | this.lng = lng; 23 | this.lat = lat; 24 | } 25 | 26 | public LngLatPoint convert2LngLat() { 27 | return GeoUtils.Mercator2LngLat(this); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/geo/PixelPoint.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.geo; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class PixelPoint { 7 | 8 | private Double x; 9 | private Double y; 10 | 11 | public PixelPoint() { 12 | 13 | } 14 | 15 | public PixelPoint(double x, double y) { 16 | this.x = x; 17 | this.y = y; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/geo/Polygon.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.geo; 2 | 3 | import java.io.Serializable; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import lombok.Data; 8 | 9 | @Data 10 | public class Polygon implements Serializable { 11 | 12 | private static final long serialVersionUID = 8429062630741585169L; 13 | 14 | ArrayList path; 15 | 16 | public Polygon() { 17 | 18 | } 19 | 20 | public Polygon(List path) { 21 | this.path = (ArrayList) path; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/geo/Tile.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.geo; 2 | 3 | import java.io.Serial; 4 | import java.io.Serializable; 5 | 6 | import lombok.Data; 7 | 8 | @Data 9 | public class Tile implements Serializable { 10 | 11 | @Serial 12 | private static final long serialVersionUID = -3598715656639420131L; 13 | 14 | private Integer z; 15 | private Long x; 16 | private Long y; 17 | 18 | private MercatorPoint topLeft; 19 | private MercatorPoint topRight; 20 | private MercatorPoint bottomLeft; 21 | private MercatorPoint bottomRight; 22 | 23 | public Tile() { 24 | 25 | } 26 | 27 | public Tile(int z, long x, long y) { 28 | this.z = z; 29 | this.x = x; 30 | this.y = y; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/page/PageTileUrlBack.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.page; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class PageTileUrlBack { 7 | 8 | private String url; 9 | private Boolean support; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/result/BlockAsyncTaskResult.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.result; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class BlockAsyncTaskResult { 7 | 8 | private Integer flag; 9 | private Long xStart; 10 | private Long xEnd; 11 | private Long yStart; 12 | private Long yEnd; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/result/DownloadResult.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.result; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class DownloadResult { 7 | 8 | private byte[] imgData; 9 | private boolean success; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/result/ImageMergeAsyncTaskResult.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.result; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | 6 | @Data 7 | @EqualsAndHashCode(callSuper = false) 8 | public class ImageMergeAsyncTaskResult extends BlockAsyncTaskResult { 9 | 10 | private Integer divideXIndex; 11 | private Integer divideYIndex; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/result/ProcessInitializationResult.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.result; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class ProcessInitializationResult { 7 | 8 | private Integer perc; 9 | private String beanName; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/task/ErrorTileEntity.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.task; 2 | 3 | import java.io.Serial; 4 | import java.io.Serializable; 5 | 6 | import com.jmd.model.geo.Tile; 7 | 8 | import lombok.Data; 9 | 10 | @Data 11 | public class ErrorTileEntity implements Serializable{ 12 | 13 | @Serial 14 | private static final long serialVersionUID = 3473523097592663626L; 15 | 16 | private String keyName; 17 | private String blockName; 18 | private Tile tile; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/task/MergeProgressEntity.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.task; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class MergeProgressEntity { 7 | 8 | private Long allPixel; 9 | private Long runPixel; 10 | private Double perc; 11 | private Integer restSec; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/task/TaskAllInfoEntity.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.task; 2 | 3 | import java.io.Serial; 4 | import java.io.Serializable; 5 | import java.util.concurrent.ConcurrentHashMap; 6 | 7 | import lombok.Data; 8 | 9 | @Data 10 | public class TaskAllInfoEntity implements Serializable { 11 | 12 | @Serial 13 | private static final long serialVersionUID = 6301744429585359593L; 14 | 15 | private String tileUrl; 16 | private String tileName; 17 | private String mapType; 18 | private Integer imgType; 19 | private String savePath; 20 | private String pathStyle; 21 | private Boolean isCoverExists; 22 | private Boolean isMergeTile; 23 | private Integer mergeType; 24 | private Integer errorHandlerType; 25 | private Long allRealCount; 26 | private Long allRunCount; 27 | private ConcurrentHashMap eachLayerTask; 28 | private ConcurrentHashMap errorTiles; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/task/TaskBlockDivide.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.task; 2 | 3 | import java.util.ArrayList; 4 | 5 | import lombok.Data; 6 | 7 | @Data 8 | public class TaskBlockDivide { 9 | 10 | private Long countX; 11 | private Long countY; 12 | private ArrayList divideX; 13 | private ArrayList divideY; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/task/TaskBlockEntity.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.task; 2 | 3 | import java.io.Serial; 4 | import java.io.Serializable; 5 | 6 | import lombok.Data; 7 | 8 | @Data 9 | public class TaskBlockEntity implements Serializable { 10 | 11 | @Serial 12 | private static final long serialVersionUID = -2871903479117630871L; 13 | 14 | private String name; 15 | private Integer z; 16 | 17 | private Long xStart; 18 | private Long xEnd; 19 | private Long yStart; 20 | private Long yEnd; 21 | 22 | private Long realCount; 23 | 24 | private Long xRun; 25 | private Long yRun; 26 | private Long runCount; 27 | 28 | public TaskBlockEntity() { 29 | 30 | } 31 | 32 | public TaskBlockEntity( 33 | String name, 34 | Integer z, 35 | Long xStart, Long xEnd, 36 | Long yStart, Long yEnd, 37 | Long realCount, 38 | Long xRun, 39 | Long yRun, 40 | Long runCount 41 | ) { 42 | this.name = name; 43 | this.z = z; 44 | this.xStart = xStart; 45 | this.xEnd = xEnd; 46 | this.yStart = yStart; 47 | this.yEnd = yEnd; 48 | this.realCount = realCount; 49 | this.xRun = xRun; 50 | this.yRun = yRun; 51 | this.runCount = runCount; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/task/TaskCreateEntity.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.task; 2 | 3 | import java.util.List; 4 | 5 | import com.jmd.model.geo.Polygon; 6 | 7 | import lombok.Data; 8 | 9 | @Data 10 | public class TaskCreateEntity { 11 | 12 | private List zoomList; 13 | private List polygons; 14 | private String tileUrl; 15 | private String savePath; 16 | private String tileName; 17 | private String mapType; 18 | private Integer imgType; 19 | private String pathStyle; 20 | private Boolean isCoverExists; 21 | private Boolean isMergeTile; 22 | private Integer mergeType; 23 | private Integer errorHandlerType; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/task/TaskExecEntity.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.task; 2 | 3 | import java.util.List; 4 | 5 | import com.jmd.callback.TileDownloadedCallback; 6 | import com.jmd.model.geo.Polygon; 7 | 8 | import lombok.Data; 9 | 10 | @Data 11 | public class TaskExecEntity { 12 | 13 | private String tileName; 14 | private Integer z; 15 | private Long xStart; 16 | private Long xEnd; 17 | private Long yStart; 18 | private Long yEnd; 19 | private Long xRun; 20 | private Long yRun; 21 | private Long startCount; 22 | private List polygons; 23 | private String downloadUrl; 24 | private Integer imgType; 25 | private String pathStyle; 26 | private String savePath; 27 | private Boolean isCoverExists; 28 | private TileDownloadedCallback tileCB; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/task/TaskInstEntity.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.task; 2 | 3 | import java.io.Serial; 4 | import java.io.Serializable; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | 9 | import com.jmd.model.geo.Polygon; 10 | 11 | import lombok.Data; 12 | 13 | @Data 14 | public class TaskInstEntity implements Serializable { 15 | 16 | @Serial 17 | private static final long serialVersionUID = -7964576148008799649L; 18 | 19 | private Integer z; 20 | private List polygons; 21 | private ArrayList divideX; 22 | private ArrayList divideY; 23 | private ConcurrentHashMap blocks; 24 | private Long allCount; 25 | private Long realCount; 26 | 27 | private Long xStart; 28 | private Long xEnd; 29 | private Long yStart; 30 | private Long yEnd; 31 | 32 | private Boolean needMerge; 33 | private Boolean isMerged; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/task/TaskProgressEntity.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.task; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class TaskProgressEntity { 7 | 8 | private Long lastCount; 9 | private Long currentCount; 10 | private Double perc; 11 | 12 | public TaskProgressEntity() { 13 | 14 | } 15 | 16 | public TaskProgressEntity(long lastCount, long currentCount, double perc) { 17 | this.lastCount = lastCount; 18 | this.currentCount = currentCount; 19 | this.perc = perc; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/task/TaskStatusEnum.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.task; 2 | 3 | public enum TaskStatusEnum { 4 | 5 | START, 6 | PAUSE, 7 | CONTINUE, 8 | FINISH, 9 | CANCEL, 10 | 11 | } 12 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/theme/ThemeEntity.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.theme; 2 | 3 | import java.util.List; 4 | 5 | import lombok.Data; 6 | 7 | @Data 8 | public class ThemeEntity { 9 | 10 | private Integer type; 11 | private String name; 12 | private String clazz; 13 | private List sub; 14 | 15 | public ThemeEntity(String name, List sub) { 16 | this.name = name; 17 | this.sub = sub; 18 | } 19 | 20 | public ThemeEntity(int type, String name, String clazz) { 21 | this.type = type; 22 | this.name = name; 23 | this.clazz = clazz; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/model/tile/TileViewParam.java: -------------------------------------------------------------------------------- 1 | package com.jmd.model.tile; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class TileViewParam { 7 | 8 | private String path; 9 | private String pathStyle; 10 | private Integer type; 11 | 12 | public TileViewParam() { 13 | 14 | } 15 | 16 | public TileViewParam(String path, String pathStyle, Integer type) { 17 | this.path = path; 18 | this.pathStyle = pathStyle; 19 | this.type = type; 20 | } 21 | 22 | public boolean check() { 23 | return this.path != null && this.pathStyle != null && this.type != null; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/os/CPUMonitor.java: -------------------------------------------------------------------------------- 1 | package com.jmd.os; 2 | 3 | import java.lang.management.ManagementFactory; 4 | 5 | import org.springframework.stereotype.Component; 6 | 7 | import com.sun.management.OperatingSystemMXBean; 8 | 9 | @Component 10 | public class CPUMonitor { 11 | 12 | private final java.lang.management.OperatingSystemMXBean java_osMxBean = ManagementFactory.getOperatingSystemMXBean(); 13 | private final java.lang.management.ThreadMXBean java_threadBean = ManagementFactory.getThreadMXBean(); 14 | private final com.sun.management.OperatingSystemMXBean sun_osMxBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); 15 | private long preTime = System.nanoTime(); 16 | private long preUsedTime = 0; 17 | 18 | public double getSystemCpuLoad() { 19 | return sun_osMxBean.getCpuLoad(); 20 | } 21 | 22 | public double getProcessCpuLoad() { 23 | return sun_osMxBean.getProcessCpuLoad(); 24 | } 25 | 26 | public double getProcessCpuUsage_Old() { 27 | long totalTime = 0; 28 | for (long id : java_threadBean.getAllThreadIds()) { 29 | totalTime += java_threadBean.getThreadCpuTime(id); 30 | } 31 | long curtime = System.nanoTime(); 32 | long usedTime = totalTime - preUsedTime; 33 | long totalPassedTime = curtime - preTime; 34 | preTime = curtime; 35 | preUsedTime = totalTime; 36 | return (((double) usedTime) / totalPassedTime / java_osMxBean.getAvailableProcessors()) * 100; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/os/RAMMonitor.java: -------------------------------------------------------------------------------- 1 | package com.jmd.os; 2 | 3 | import java.text.DecimalFormat; 4 | 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | public class RAMMonitor { 9 | 10 | private DecimalFormat df1 = new DecimalFormat("#.#"); 11 | 12 | public String getUsedRam() { 13 | double total = Double.valueOf(Runtime.getRuntime().totalMemory()); 14 | return df1.format(total / 1024.0 / 1024.0) + "MB"; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/rx/Topic.kt: -------------------------------------------------------------------------------- 1 | package com.jmd.rx 2 | 3 | enum class Topic { 4 | 5 | APPLICATION_START_FINISH, 6 | 7 | CHANGE_THEME, 8 | 9 | UPDATE_THEME_TEXT, 10 | UPDATE_UI, 11 | UPDATE_PROXY_STATUS, 12 | 13 | MAIN_FRAME_SELECTED_INDEX, 14 | MAIN_FRAME_SHOW, 15 | MAIN_FRAME_HIDE, 16 | FLOATING_WINDOW_TOGGLE, 17 | SET_INTERVAL, 18 | CLEAR_INTERVAL, 19 | 20 | TASK_STATUS_CURRENT, 21 | TASK_STATUS_MAP_TYPE, 22 | TASK_STATUS_LAYERS, 23 | TASK_STATUS_SAVE_PATH, 24 | TASK_STATUS_PATH_STYLE, 25 | TASK_STATUS_IS_COVER_EXIST, 26 | TASK_STATUS_IMG_TYPE, 27 | TASK_STATUS_TILE_ALL_COUNT, 28 | TASK_STATUS_TILE_DOWNLOADED_COUNT, 29 | TASK_STATUS_PROGRESS, 30 | TASK_STATUS_ENUM, 31 | 32 | CPU_PERCENTAGE_DRAW_SYSTEM, 33 | CPU_PERCENTAGE_DRAW_PROCESS, 34 | CPU_PERCENTAGE_CLEAR, 35 | 36 | RESOURCE_USAGE_THREAD_COUNT, 37 | RESOURCE_USAGE_DOWNLOAD_SPEED, 38 | RESOURCE_USAGE_DOWNLOAD_PER_SEC_COUNT, 39 | RESOURCE_USAGE_SYSTEM_CPU_USAGE, 40 | RESOURCE_USAGE_PROCESS_CPU_USAGE, 41 | RESOURCE_USAGE_CLEAR, 42 | 43 | TILE_MERGE_PROCESS_PIXEL_COUNT, 44 | TILE_MERGE_PROCESS_THREAD, 45 | TILE_MERGE_PROCESS_PROGRESS, 46 | TILE_MERGE_PROCESS_CLEAR, 47 | 48 | DOWNLOAD_CONSOLE_PROGRESS, 49 | DOWNLOAD_CONSOLE_LOG, 50 | DOWNLOAD_CONSOLE_CLEAR, 51 | DOWNLOAD_CONFIG_FRAME_ZOOM_SELECTED, 52 | DOWNLOAD_CONFIG_FRAME_PATH_SELECTED, 53 | 54 | ADD_NEW_LAYER, 55 | REMOVE_ADDED_LAYER, 56 | 57 | OPEN_TILE_VIEW, 58 | 59 | OPEN_BROWSER_DEV_TOOL, 60 | 61 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/rx/callback/OnMessageCallback.java: -------------------------------------------------------------------------------- 1 | package com.jmd.rx.callback; 2 | 3 | public interface OnMessageCallback { 4 | 5 | void exec(T msg); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/rx/callback/OnSubscribeCallback.java: -------------------------------------------------------------------------------- 1 | package com.jmd.rx.callback; 2 | 3 | import com.jmd.rx.Topic; 4 | import io.reactivex.rxjava3.subjects.PublishSubject; 5 | 6 | public interface OnSubscribeCallback { 7 | 8 | void exec(Topic topic, PublishSubject subject); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/rx/client/InnerMqClient.java: -------------------------------------------------------------------------------- 1 | package com.jmd.rx.client; 2 | 3 | import com.jmd.rx.Topic; 4 | import com.jmd.rx.callback.OnMessageCallback; 5 | import com.jmd.rx.callback.OnSubscribeCallback; 6 | import io.reactivex.rxjava3.subjects.PublishSubject; 7 | 8 | public interface InnerMqClient { 9 | 10 | void setOnSubscribeCallback(OnSubscribeCallback onSubscribeCallback); 11 | 12 | String getId(); 13 | 14 | PublishSubject getSubject(Topic topic); 15 | 16 | boolean isDestroyed(); 17 | 18 | void sub(Topic topic, OnMessageCallback callback); 19 | 20 | void destroy(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/rx/client/impl/NormalInnerMqClient.java: -------------------------------------------------------------------------------- 1 | package com.jmd.rx.client.impl; 2 | 3 | import com.jmd.rx.Topic; 4 | import com.jmd.rx.client.InnerMqClient; 5 | import com.jmd.rx.callback.OnMessageCallback; 6 | import com.jmd.rx.callback.OnSubscribeCallback; 7 | import io.reactivex.rxjava3.disposables.CompositeDisposable; 8 | import io.reactivex.rxjava3.subjects.PublishSubject; 9 | 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | public class NormalInnerMqClient implements InnerMqClient { 14 | 15 | public Map> subjects = new HashMap<>(); 16 | private final CompositeDisposable compositeDisposable = new CompositeDisposable(); 17 | 18 | private final String id; 19 | private OnSubscribeCallback onSubscribeCallback; 20 | private boolean destroyed = false; 21 | 22 | public NormalInnerMqClient(String id) { 23 | this.id = id; 24 | } 25 | 26 | @Override 27 | public void setOnSubscribeCallback(OnSubscribeCallback onSubscribeCallback) { 28 | this.onSubscribeCallback = onSubscribeCallback; 29 | } 30 | 31 | @Override 32 | public String getId() { 33 | return this.id; 34 | } 35 | 36 | @Override 37 | public PublishSubject getSubject(Topic topic) { 38 | return this.subjects.get(topic); 39 | } 40 | 41 | @Override 42 | public boolean isDestroyed() { 43 | return this.destroyed; 44 | } 45 | 46 | @Override 47 | @SuppressWarnings("unchecked") 48 | public void sub(Topic topic, OnMessageCallback callback) { 49 | var subject = subjects.computeIfAbsent(topic, k -> PublishSubject.create()); 50 | this.compositeDisposable.add(subject.subscribe((msg) -> { 51 | callback.exec((T) msg); 52 | })); 53 | this.onSubscribeCallback.exec(topic, subject); 54 | } 55 | 56 | @Override 57 | public void destroy() { 58 | this.destroyed = true; 59 | this.subjects.clear(); 60 | if (!this.compositeDisposable.isDisposed()) { 61 | this.compositeDisposable.dispose(); 62 | } 63 | } 64 | 65 | } 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/task/TaskState.java: -------------------------------------------------------------------------------- 1 | package com.jmd.task; 2 | 3 | public class TaskState { 4 | 5 | public static boolean IS_TASKING = false; 6 | public static boolean IS_PAUSING = false; 7 | public static boolean IS_CANCEL = false; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/task/TileMergeMatWrap.java: -------------------------------------------------------------------------------- 1 | package com.jmd.task; 2 | 3 | import org.apache.commons.io.FileUtils; 4 | import org.opencv.core.CvType; 5 | import org.opencv.core.Mat; 6 | import org.opencv.core.Range; 7 | import org.opencv.imgcodecs.Imgcodecs; 8 | import org.opencv.imgproc.Imgproc; 9 | import com.jmd.common.StaticVar; 10 | 11 | import lombok.Getter; 12 | 13 | import java.io.File; 14 | import java.io.IOException; 15 | 16 | public class TileMergeMatWrap { 17 | 18 | private Mat des = null; 19 | 20 | private int width; 21 | private int height; 22 | 23 | @Getter 24 | private long allPixel = 0L; 25 | @Getter 26 | private long runPixel = 0L; 27 | 28 | public void init(int width, int height) { 29 | this.width = width; 30 | this.height = height; 31 | /* 32 | * CV_8uc1 单颜色通道 8位
33 | * CV_8uc2 2颜色通道 16位
34 | * CV_8uc3 3颜色通道 24位
35 | * CV_8uc4 4颜色通道 32位
36 | */ 37 | // CV_8UC4为支持透明PNG的RGBA格式 38 | this.des = Mat.zeros(height, width, CvType.CV_8UC4); 39 | // 计算总像素数量 40 | this.allPixel = (long) width * height; 41 | } 42 | 43 | public void mergeToMat(String pathAndName, long x, long y, boolean flag) { 44 | // 是否读取图像进行合并 45 | int tileWidth = StaticVar.TILE_WIDTH; 46 | int tileHeight = StaticVar.TILE_HEIGHT; 47 | if (flag) { 48 | // 读取图片 49 | var tileMat = Imgcodecs.imread(pathAndName, Imgcodecs.IMREAD_UNCHANGED); 50 | try { 51 | // 转换图片至RGBA格式 52 | Imgproc.cvtColor(tileMat, tileMat, Imgproc.COLOR_BGR2BGRA); 53 | // 确定坐标位置 54 | var rectForDes = this.des 55 | .colRange(new Range((int) x, (int) x + tileWidth)) 56 | .rowRange(new Range((int) y, (int) y + tileHeight)); 57 | // 填充至合并大图 58 | tileMat.copyTo(rectForDes); 59 | } catch (Exception ignored) { 60 | 61 | } 62 | } 63 | // 完成后计算已合并的像素数量 64 | this.runPixel += (long) tileWidth * tileHeight; 65 | } 66 | 67 | public void output(String path, String name, int type) throws IOException { 68 | String suffix = "png"; 69 | if (type != 3) { 70 | if (this.width < 16383 && this.height < 16383) { 71 | if (type == 0 || type == 1) { 72 | // 自动,WEBP 73 | suffix = "webp"; 74 | } else if (type == 2) { 75 | // 自动,JPG 76 | suffix = "jpg"; 77 | } 78 | } else if (this.width < 65535 && this.height < 65535) { 79 | // 自动,WEBP,JPG 80 | if (type == 0 || type == 1 || type == 2) { 81 | suffix = "jpg"; 82 | } 83 | } 84 | } 85 | String out = path + name + "." + suffix; 86 | FileUtils.createParentDirectories(new File(out)); 87 | Imgcodecs.imwrite(out, this.des); 88 | } 89 | 90 | public void destroy() { 91 | this.des.release(); 92 | this.des = null; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ui/common/CommonContainerPanel.kt: -------------------------------------------------------------------------------- 1 | package com.jmd.ui.common 2 | 3 | import com.jmd.common.StaticVar 4 | import java.awt.BorderLayout 5 | import java.awt.Component 6 | import java.io.Serial 7 | import javax.swing.JPanel 8 | import javax.swing.border.TitledBorder 9 | 10 | class CommonContainerPanel(title: String?) : JPanel() { 11 | 12 | companion object { 13 | @Serial 14 | private val serialVersionUID = 6628330531744102560L 15 | } 16 | 17 | init { 18 | if (title != null) { 19 | border = TitledBorder(null, title, TitledBorder.LEADING, TitledBorder.TOP, 20 | StaticVar.FONT_SourceHanSansCNNormal_12, null) 21 | } 22 | this.layout = BorderLayout() 23 | } 24 | 25 | // 预留此方法的目的为适配 eclipse 的 window build 正确识别 26 | fun addContent(comp: Component) { 27 | super.add(comp, BorderLayout.CENTER) 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ui/common/CommonSubFrame.kt: -------------------------------------------------------------------------------- 1 | package com.jmd.ui.common 2 | 3 | import com.jmd.ApplicationStore 4 | import com.jmd.rx.Topic 5 | import com.jmd.rx.callback.OnMessageCallback 6 | import com.jmd.rx.client.InnerMqClient 7 | import com.jmd.rx.service.InnerMqService 8 | import com.jmd.util.ImageUtils 9 | import java.io.Serial 10 | import javax.swing.JFrame 11 | import javax.swing.SwingUtilities 12 | 13 | abstract class CommonSubFrame : JFrame() { 14 | 15 | companion object { 16 | @Serial 17 | private val serialVersionUID = -3945359489263563093L 18 | } 19 | 20 | private val innerMqService = InnerMqService.getInstance() 21 | private var client: InnerMqClient? = null 22 | 23 | init { 24 | /* 任务栏图标 */ 25 | this.iconImage = ImageUtils.getResourceImage("assets/icon/map.png") 26 | this.defaultCloseOperation = DISPOSE_ON_CLOSE 27 | try { 28 | subInnerMqMessage() 29 | } catch (e: Exception) { 30 | e.printStackTrace() 31 | } 32 | } 33 | 34 | protected open fun destroy() { 35 | this.innerMqService?.destroyClient(this.client) 36 | } 37 | 38 | @Throws(Exception::class) 39 | private fun subInnerMqMessage() { 40 | this.client = innerMqService.createClient() 41 | this.client?.sub( 42 | Topic.UPDATE_UI, OnMessageCallback { res: Any? -> 43 | SwingUtilities.invokeLater { SwingUtilities.updateComponentTreeUI(this) } 44 | } 45 | ) 46 | } 47 | 48 | override fun setVisible(b: Boolean) { 49 | if (b) { 50 | val lx = ApplicationStore.MAIN_FRAME_LOCATION_X 51 | val ly = ApplicationStore.MAIN_FRAME_LOCATION_Y 52 | val mw = ApplicationStore.MAIN_FRAME_WIDTH 53 | val mh = ApplicationStore.MAIN_FRAME_HEIGHT 54 | val x = lx - this.size.getWidth().toInt() / 2 + mw / 2 55 | val y = ly - this.size.getHeight().toInt() / 2 + mh / 2 56 | this.setLocation(x, y) 57 | } 58 | super.setVisible(b) 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ui/common/IconLabel.kt: -------------------------------------------------------------------------------- 1 | package com.jmd.ui.common 2 | 3 | import java.io.Serial 4 | import javax.swing.Icon 5 | import javax.swing.JLabel 6 | 7 | class IconLabel(path: String) : JLabel() { 8 | 9 | companion object { 10 | @Serial 11 | private val serialVersionUID = -2643890482143441343L 12 | } 13 | 14 | private val icon: AutoScalingIcon 15 | 16 | init { 17 | this.icon = AutoScalingIcon(path, AutoScalingIcon.XPosition.LEFT, AutoScalingIcon.YPosition.TOP, 0, 0); 18 | this.setIcon(this.icon) 19 | } 20 | 21 | override fun getIcon(): Icon { 22 | return this.icon 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ui/common/NoScalingIcon.kt: -------------------------------------------------------------------------------- 1 | package com.jmd.ui.common 2 | 3 | import com.jmd.util.MyFileUtils 4 | import java.awt.Component 5 | import java.awt.Graphics 6 | import java.awt.Graphics2D 7 | import java.awt.Image 8 | import java.awt.geom.AffineTransform 9 | import javax.swing.Icon 10 | import javax.swing.ImageIcon 11 | 12 | class NoScalingIcon(width: Int, height: Int, path: String) : Icon { 13 | 14 | private val icon = ImageIcon() 15 | 16 | init { 17 | val originIcon = ImageIcon(MyFileUtils.getResourceFileBytes(path)) 18 | this.icon.image = originIcon.image.getScaledInstance(width, height, Image.SCALE_SMOOTH) 19 | } 20 | 21 | override fun getIconWidth(): Int { 22 | return this.icon.iconWidth 23 | } 24 | 25 | override fun getIconHeight(): Int { 26 | return this.icon.iconHeight 27 | } 28 | 29 | override fun paintIcon(c: Component, g: Graphics, x: Int, y: Int) { 30 | 31 | val g2d = g.create() as Graphics2D 32 | val at = g2d.transform 33 | 34 | val scaleX = (x * at.scaleX).toInt() 35 | val scaleY = (y * at.scaleY).toInt() 36 | val offsetX = (this.icon.iconWidth * (at.scaleX - 1) / 2).toInt() 37 | val offsetY = (this.icon.iconHeight * (at.scaleY - 1) / 2).toInt() 38 | val locationX = scaleX + offsetX 39 | val locationY = scaleY + offsetY 40 | 41 | // Reset scaling to 1.0 by concatenating an inverse scale transform 42 | val scaled = AffineTransform.getScaleInstance(1.0 / at.scaleX, 1.0 / at.scaleY) 43 | at.concatenate(scaled) 44 | g2d.transform = at 45 | 46 | this.icon.paintIcon(c, g2d, locationX, locationY) 47 | g2d.dispose() 48 | 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ui/frame/info/DonateFrame.java: -------------------------------------------------------------------------------- 1 | package com.jmd.ui.frame.info; 2 | 3 | import java.awt.Dimension; 4 | import java.io.Serial; 5 | 6 | import javax.swing.*; 7 | 8 | import com.jmd.ui.common.CommonSubFrame; 9 | import com.jmd.ui.common.IconLabel; 10 | import org.springframework.stereotype.Component; 11 | 12 | @Component 13 | public class DonateFrame extends CommonSubFrame { 14 | 15 | @Serial 16 | private static final long serialVersionUID = -7739920320485676764L; 17 | 18 | public DonateFrame() { 19 | 20 | this.getContentPane().setLayout(null); 21 | 22 | var panel = new JPanel(); 23 | panel.setBounds(0, 0, 633, 450); 24 | panel.setLayout(null); 25 | 26 | var alipayImageLabel = new IconLabel("assets/donate/alipay.jpg"); 27 | alipayImageLabel.setBounds(0, 0, 296, 460); 28 | panel.add(alipayImageLabel); 29 | 30 | var wechatImageLabel = new IconLabel("assets/donate/wechat.png"); 31 | wechatImageLabel.setBounds(296, 0, 337, 460); 32 | panel.add(wechatImageLabel); 33 | getContentPane().add(panel); 34 | 35 | this.setTitle("捐赠开发者(非强制,不影响软件使用)"); 36 | this.setSize(new Dimension(646, 486)); 37 | this.setVisible(false); 38 | this.setResizable(false); 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ui/tab/a_map/panel/BottomInfoPanel.java: -------------------------------------------------------------------------------- 1 | package com.jmd.ui.tab.a_map.panel; 2 | 3 | import javax.swing.JPanel; 4 | 5 | import com.jmd.browser.core.ChromiumEmbeddedCore; 6 | import org.springframework.stereotype.Component; 7 | 8 | import com.jmd.common.StaticVar; 9 | 10 | import javax.swing.JLabel; 11 | import java.awt.BorderLayout; 12 | import java.io.Serial; 13 | 14 | @Component 15 | public class BottomInfoPanel extends JPanel { 16 | 17 | @Serial 18 | private static final long serialVersionUID = -5223551680329511378L; 19 | 20 | public BottomInfoPanel() { 21 | 22 | var version = " JetBrains Runtime: " + 23 | System.getProperty("java.vm.version") + 24 | ", " + 25 | "Chromium Embedded Framework (CEF), " + 26 | "ChromeVersion: " + 27 | ChromiumEmbeddedCore.Companion.getInstance().getVersion(); 28 | 29 | this.setLayout(new BorderLayout(0, 0)); 30 | JLabel leftLabel = new JLabel(version); 31 | leftLabel.setFont(StaticVar.FONT_SourceHanSansCNNormal_12); 32 | this.add(leftLabel, BorderLayout.WEST); 33 | 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ui/tab/a_map/panel/MapControlBrowserPanel.java: -------------------------------------------------------------------------------- 1 | package com.jmd.ui.tab.a_map.panel; 2 | 3 | import java.io.Serial; 4 | 5 | import com.jmd.rx.Topic; 6 | import com.jmd.rx.client.InnerMqClient; 7 | import com.jmd.rx.service.InnerMqService; 8 | import com.jmd.ui.common.BrowserViewPanel; 9 | import com.jmd.util.CommonUtils; 10 | import com.jmd.web.common.WsSendData; 11 | import com.jmd.web.websocket.handler.MapWebSocketHandler; 12 | import jakarta.annotation.PostConstruct; 13 | import jakarta.annotation.PreDestroy; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.beans.factory.annotation.Value; 16 | import org.springframework.stereotype.Component; 17 | 18 | @Component 19 | public class MapControlBrowserPanel extends BrowserViewPanel { 20 | 21 | @Serial 22 | private static final long serialVersionUID = 5503359353536143127L; 23 | 24 | private final InnerMqService innerMqService = InnerMqService.getInstance(); 25 | private InnerMqClient client; 26 | 27 | @Value("${setting.web.prod}") 28 | private boolean prod; 29 | 30 | @Autowired 31 | private MapWebSocketHandler wsHandler; 32 | 33 | public MapControlBrowserPanel() { 34 | super("/map-control", "WebView初始化"); 35 | } 36 | 37 | @PostConstruct 38 | private void init() { 39 | try { 40 | this.subInnerMqMessage(); 41 | } catch (Exception e) { 42 | e.printStackTrace(); 43 | } 44 | } 45 | 46 | @PreDestroy 47 | protected void destroy() { 48 | this.innerMqService.destroyClient(this.client); 49 | } 50 | 51 | private void subInnerMqMessage() throws Exception { 52 | this.client = innerMqService.createClient(); 53 | this.client.sub(Topic.APPLICATION_START_FINISH, (res) -> { 54 | if (this.isLoaded()) { 55 | this.reload(); 56 | } else { 57 | this.load(this.prod); 58 | } 59 | }); 60 | this.client.sub(Topic.OPEN_BROWSER_DEV_TOOL, (res) -> { 61 | this.toggleDevTools(); 62 | }); 63 | } 64 | 65 | public void clearLocalStorage() { 66 | this.execJS("localStorage.removeItem(\"jmd-config\")"); 67 | } 68 | 69 | public void sendMessageByWebsocket(String topic, String message) { 70 | this.wsHandler.send(new WsSendData(topic, message)); 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ui/tab/a_map/panel/StatusInfoPanel.java: -------------------------------------------------------------------------------- 1 | package com.jmd.ui.tab.a_map.panel; 2 | 3 | import com.jmd.common.StaticVar; 4 | import com.jmd.http.ProxySetting; 5 | import com.jmd.rx.Topic; 6 | import com.jmd.rx.client.InnerMqClient; 7 | import com.jmd.rx.service.InnerMqService; 8 | import jakarta.annotation.PostConstruct; 9 | import jakarta.annotation.PreDestroy; 10 | import org.springframework.stereotype.Component; 11 | 12 | import javax.swing.*; 13 | import javax.swing.border.TitledBorder; 14 | import java.awt.*; 15 | import java.io.Serial; 16 | 17 | @Component 18 | public class StatusInfoPanel extends JPanel { 19 | 20 | @Serial 21 | private static final long serialVersionUID = 2553207209432671195L; 22 | 23 | private final InnerMqService innerMqService = InnerMqService.getInstance(); 24 | private InnerMqClient client; 25 | 26 | private final JLabel proxyStatusValue; 27 | 28 | public StatusInfoPanel() { 29 | 30 | JLabel proxyStatusLabel = new JLabel("代理状态:"); 31 | proxyStatusLabel.setFont(StaticVar.FONT_SourceHanSansCNNormal_12); 32 | 33 | this.proxyStatusValue = new JLabel(""); 34 | proxyStatusLabel.setFont(StaticVar.FONT_SourceHanSansCNNormal_12); 35 | 36 | GroupLayout groupLayout = new GroupLayout(this); 37 | groupLayout.setHorizontalGroup(groupLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 38 | .addGroup(groupLayout.createSequentialGroup().addContainerGap().addComponent(proxyStatusLabel) 39 | .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addComponent(proxyStatusValue) 40 | .addContainerGap(50, Short.MAX_VALUE))); 41 | groupLayout 42 | .setVerticalGroup(groupLayout.createParallelGroup(GroupLayout.Alignment.LEADING) 43 | .addGroup(groupLayout.createSequentialGroup().addContainerGap() 44 | .addGroup(groupLayout.createParallelGroup(GroupLayout.Alignment.BASELINE) 45 | .addComponent(proxyStatusLabel).addComponent(proxyStatusValue)) 46 | .addContainerGap(0, Short.MAX_VALUE))); 47 | this.setLayout(groupLayout); 48 | 49 | } 50 | 51 | @PostConstruct 52 | private void init() { 53 | this.updateProxyStatus(); 54 | try { 55 | this.subInnerMqMessage(); 56 | } catch (Exception e) { 57 | e.printStackTrace(); 58 | } 59 | } 60 | 61 | @PreDestroy 62 | protected void destroy() { 63 | this.innerMqService.destroyClient(this.client); 64 | } 65 | 66 | private void subInnerMqMessage() throws Exception { 67 | this.client = this.innerMqService.createClient(); 68 | this.client.sub(Topic.UPDATE_PROXY_STATUS, (res) -> { 69 | this.updateProxyStatus(); 70 | }); 71 | } 72 | 73 | public void updateProxyStatus() { 74 | SwingUtilities.invokeLater(() -> { 75 | if (ProxySetting.enable) { 76 | proxyStatusValue.setText("开启"); 77 | proxyStatusValue.setForeground(Color.GREEN); 78 | } else { 79 | proxyStatusValue.setText("关闭"); 80 | proxyStatusValue.setForeground(Color.BLUE); 81 | } 82 | }); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ui/tab/b_download/panel/TaskLogPanel.java: -------------------------------------------------------------------------------- 1 | package com.jmd.ui.tab.b_download.panel; 2 | 3 | import com.jmd.common.StaticVar; 4 | import com.jmd.rx.Topic; 5 | import com.jmd.rx.client.InnerMqClient; 6 | import com.jmd.rx.service.InnerMqService; 7 | import jakarta.annotation.PostConstruct; 8 | import jakarta.annotation.PreDestroy; 9 | import org.springframework.stereotype.Component; 10 | 11 | import javax.swing.*; 12 | import java.awt.*; 13 | import java.io.Serial; 14 | import java.text.SimpleDateFormat; 15 | 16 | @Component 17 | public class TaskLogPanel extends JPanel { 18 | 19 | @Serial 20 | private static final long serialVersionUID = -1939864312267681290L; 21 | 22 | private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 23 | private final InnerMqService innerMqService = InnerMqService.getInstance(); 24 | private InnerMqClient client; 25 | 26 | private final JTextArea textArea; 27 | 28 | public TaskLogPanel() { 29 | 30 | this.setLayout(new BorderLayout()); 31 | 32 | var logScrollPane = new JScrollPane(); 33 | this.add(logScrollPane, BorderLayout.CENTER); 34 | 35 | this.textArea = new JTextArea(); 36 | this.textArea.setEditable(false); 37 | this.textArea.setFocusable(false); 38 | this.textArea.setFont(StaticVar.FONT_SourceHanSansCNNormal_13); 39 | logScrollPane.setViewportView(this.textArea); 40 | 41 | } 42 | 43 | @PostConstruct 44 | private void init() { 45 | try { 46 | this.subInnerMqMessage(); 47 | } catch (Exception e) { 48 | e.printStackTrace(); 49 | } 50 | } 51 | 52 | @PreDestroy 53 | protected void destroy() { 54 | this.innerMqService.destroyClient(this.client); 55 | } 56 | 57 | private void subInnerMqMessage() throws Exception { 58 | this.client = this.innerMqService.createClient(); 59 | this.client.sub(Topic.DOWNLOAD_CONSOLE_LOG, this::consoleLog); 60 | this.client.sub(Topic.DOWNLOAD_CONSOLE_CLEAR, (res) -> { 61 | clearConsole(); 62 | }); 63 | } 64 | 65 | public void consoleLog(String log) { 66 | var time = "[" + this.sdf.format(System.currentTimeMillis()) + "]"; 67 | var content = time + " " + log; 68 | SwingUtilities.invokeLater(() -> { 69 | this.textArea.append(content + "\n"); 70 | this.textArea.setCaretPosition(this.textArea.getText().length()); 71 | }); 72 | } 73 | 74 | public void clearConsole() { 75 | SwingUtilities.invokeLater(() -> { 76 | this.textArea.setText(""); 77 | }); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ui/tab/b_download/panel/TaskProgressPanel.java: -------------------------------------------------------------------------------- 1 | package com.jmd.ui.tab.b_download.panel; 2 | 3 | import com.jmd.rx.Topic; 4 | import com.jmd.rx.client.InnerMqClient; 5 | import com.jmd.rx.service.InnerMqService; 6 | import jakarta.annotation.PostConstruct; 7 | import jakarta.annotation.PreDestroy; 8 | import org.springframework.stereotype.Component; 9 | 10 | import javax.swing.*; 11 | import java.io.Serial; 12 | import javax.swing.GroupLayout.Alignment; 13 | 14 | @Component 15 | public class TaskProgressPanel extends JPanel { 16 | 17 | @Serial 18 | private static final long serialVersionUID = -4117937206677840485L; 19 | 20 | private final InnerMqService innerMqService = InnerMqService.getInstance(); 21 | private InnerMqClient client; 22 | 23 | private final JProgressBar progressBar; 24 | 25 | public TaskProgressPanel() { 26 | 27 | this.progressBar = new JProgressBar(); 28 | this.progressBar.setMinimum(0); 29 | this.progressBar.setMaximum(100); 30 | 31 | var groupLayout = new GroupLayout(this); 32 | groupLayout.setHorizontalGroup( 33 | groupLayout.createParallelGroup(Alignment.LEADING) 34 | .addGroup(groupLayout.createSequentialGroup() 35 | .addContainerGap() 36 | .addComponent(this.progressBar, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE) 37 | .addContainerGap()) 38 | ); 39 | groupLayout.setVerticalGroup( 40 | groupLayout.createParallelGroup(Alignment.LEADING) 41 | .addGroup(groupLayout.createSequentialGroup() 42 | .addGap(10) 43 | .addComponent(this.progressBar, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE) 44 | .addGap(10)) 45 | ); 46 | this.setLayout(groupLayout); 47 | 48 | } 49 | 50 | @PostConstruct 51 | private void init() { 52 | try { 53 | this.subInnerMqMessage(); 54 | } catch (Exception e) { 55 | e.printStackTrace(); 56 | } 57 | } 58 | 59 | @PreDestroy 60 | protected void destroy() { 61 | this.innerMqService.destroyClient(this.client); 62 | } 63 | 64 | private void subInnerMqMessage() throws Exception { 65 | this.client = this.innerMqService.createClient(); 66 | this.client.sub(Topic.DOWNLOAD_CONSOLE_PROGRESS, (res) -> { 67 | SwingUtilities.invokeLater(() -> progressBar.setValue(res)); 68 | }); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ui/tab/c_tile/panel/TileViewBrowserPanel.java: -------------------------------------------------------------------------------- 1 | package com.jmd.ui.tab.c_tile.panel; 2 | 3 | import com.jmd.model.tile.TileViewParam; 4 | import com.jmd.rx.Topic; 5 | import com.jmd.rx.client.InnerMqClient; 6 | import com.jmd.rx.service.InnerMqService; 7 | import com.jmd.ui.common.BrowserViewPanel; 8 | import com.jmd.util.CommonUtils; 9 | import jakarta.annotation.PostConstruct; 10 | import jakarta.annotation.PreDestroy; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.io.Serial; 15 | 16 | @Component 17 | public class TileViewBrowserPanel extends BrowserViewPanel { 18 | 19 | @Serial 20 | private static final long serialVersionUID = -6812120790251794674L; 21 | 22 | private final InnerMqService innerMqService = InnerMqService.getInstance(); 23 | private InnerMqClient client; 24 | 25 | @Value("${setting.web.prod}") 26 | private boolean prod; 27 | 28 | public TileViewBrowserPanel() { 29 | super("/tile-view", "请选择瓦片并加载"); 30 | } 31 | 32 | @PostConstruct 33 | private void init() { 34 | try { 35 | this.subInnerMqMessage(); 36 | } catch (Exception e) { 37 | e.printStackTrace(); 38 | } 39 | } 40 | 41 | @PreDestroy 42 | protected void destroy() { 43 | this.innerMqService.destroyClient(this.client); 44 | } 45 | 46 | private void subInnerMqMessage() throws Exception { 47 | this.client = innerMqService.createClient(); 48 | this.client.sub(Topic.OPEN_TILE_VIEW, (res) -> { 49 | if (this.isLoaded()) { 50 | this.reload(); 51 | } else { 52 | this.load(this.prod); 53 | } 54 | }); 55 | this.client.sub(Topic.OPEN_BROWSER_DEV_TOOL, (res) -> { 56 | this.toggleDevTools(); 57 | }); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/ui/tab/d_syslog/SystemLogPanel.java: -------------------------------------------------------------------------------- 1 | package com.jmd.ui.tab.d_syslog; 2 | 3 | import javax.swing.JPanel; 4 | 5 | import com.jmd.ApplicationStore; 6 | import jakarta.annotation.PostConstruct; 7 | import org.springframework.stereotype.Component; 8 | 9 | import com.jmd.common.StaticVar; 10 | 11 | import java.awt.BorderLayout; 12 | import java.io.Serial; 13 | import javax.swing.JScrollPane; 14 | 15 | @Component 16 | public class SystemLogPanel extends JPanel { 17 | 18 | @Serial 19 | private static final long serialVersionUID = 1300659845262270172L; 20 | 21 | private final JScrollPane scrollPane; 22 | 23 | public SystemLogPanel() { 24 | 25 | this.setLayout(new BorderLayout(0, 0)); 26 | 27 | var panel = new JPanel(); 28 | this.add(panel, BorderLayout.CENTER); 29 | panel.setLayout(new BorderLayout(0, 0)); 30 | 31 | this.scrollPane = new JScrollPane(); 32 | panel.add(this.scrollPane, BorderLayout.CENTER); 33 | 34 | } 35 | 36 | @PostConstruct 37 | private void init() { 38 | var textArea = ApplicationStore.consoleTextArea; 39 | textArea.setEditable(false); 40 | textArea.setFont(StaticVar.FONT_YaHeiConsolas_13); 41 | this.scrollPane.setViewportView(textArea); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/util/ConnectorUtils.java: -------------------------------------------------------------------------------- 1 | package com.jmd.util; 2 | 3 | import java.net.InetAddress; 4 | import java.net.InetSocketAddress; 5 | import java.net.Socket; 6 | 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | @Slf4j 10 | public class ConnectorUtils { 11 | 12 | private static void bindPort(String host, int port) throws Exception { 13 | Socket s = new Socket(); 14 | s.bind(new InetSocketAddress(host, port)); 15 | s.close(); 16 | } 17 | 18 | public static boolean isPortAvailable(int port) { 19 | try { 20 | bindPort("0.0.0.0", port); 21 | bindPort(InetAddress.getLocalHost().getHostAddress(), port); 22 | return true; 23 | } catch (Exception e) { 24 | log.info("Port can't use!", "" + port); 25 | return false; 26 | } 27 | } 28 | 29 | public static int findAvailablePort(int start, int end) { 30 | for (int i = start; i < end; i++) { 31 | if (isPortAvailable(i)) 32 | return i; 33 | } 34 | return -1; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/util/FontUtils.java: -------------------------------------------------------------------------------- 1 | package com.jmd.util; 2 | 3 | import java.awt.Font; 4 | import java.awt.FontFormatException; 5 | import java.io.IOException; 6 | 7 | public class FontUtils { 8 | 9 | public static Font getIconFont(String name, float size) { 10 | return getLocalFont("iconfont/" + name, Font.PLAIN, size); 11 | } 12 | 13 | // 雅黑-Consolas 14 | public static Font YaHeiConsolas(float size) { 15 | return getLocalFont("YaHei.Consolas.1.12.ttf", Font.PLAIN, size); 16 | } 17 | 18 | // 思源黑体-中文 19 | public static Font SourceHanSansCNNormal(float size) { 20 | return getLocalFont("SourceHanSansCN-Normal.ttf", Font.PLAIN, size); 21 | } 22 | 23 | // 获取本地字体 24 | private static Font getLocalFont(String name, int style, float size) { 25 | Font definedFont = null; 26 | try { 27 | var fontFile = MyFileUtils.getResourceFile("assets/font/" + name); 28 | definedFont = Font.createFont(Font.TRUETYPE_FONT, fontFile).deriveFont(style, size); 29 | } catch (FontFormatException | IOException e) { 30 | e.printStackTrace(); 31 | } 32 | return definedFont; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/util/MyFileUtils.java: -------------------------------------------------------------------------------- 1 | package com.jmd.util; 2 | 3 | import org.apache.commons.io.FileUtils; 4 | 5 | import java.io.*; 6 | 7 | public class MyFileUtils { 8 | 9 | public static File getResourceFile(String path) throws IOException { 10 | InputStream stream = MyFileUtils.class.getClassLoader().getResourceAsStream(path); 11 | File file = new File(path); 12 | assert stream != null; 13 | FileUtils.copyInputStreamToFile(stream, file); 14 | return file; 15 | } 16 | 17 | public static byte[] getResourceFileBytes(String path) throws IOException { 18 | var file = getResourceFile(path); 19 | return getFileBytes(file); 20 | } 21 | 22 | // 读取文件字节 23 | public static byte[] getFileBytes(String path) throws IOException { 24 | return getFileBytes(new File(path)); 25 | } 26 | 27 | // 读取文件字节 28 | private static byte[] getFileBytes(File file) throws IOException { 29 | if (!file.exists() || file.isDirectory()) { 30 | return new byte[0]; 31 | } 32 | // 传统IO方式 33 | //1、定义一个Byte字节数组输出流,设置大小为文件大小 34 | //2、将打开的文件输入流转换为Buffer输入流,循环 读取buffer输入流到buffer[]缓冲,并将buffer缓冲数据输入到目标输出流。 35 | //3、将目标输出流转换为字节数组。 36 | var bos = new ByteArrayOutputStream((int) file.length()); 37 | BufferedInputStream bin = null; 38 | try { 39 | bin = new BufferedInputStream(new FileInputStream(file)); 40 | byte[] buffer = new byte[1024]; 41 | while (bin.read(buffer) > 0) { 42 | bos.write(buffer); 43 | } 44 | return bos.toByteArray(); 45 | } finally { 46 | assert bin != null; 47 | bin.close(); 48 | bos.close(); 49 | } 50 | } 51 | 52 | // 对象转文件 53 | public static void saveObj2File(Object obj, String filePath) throws IOException { 54 | FileOutputStream fos = new FileOutputStream(filePath); 55 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(fos); 56 | objectOutputStream.writeObject(obj); 57 | objectOutputStream.close(); 58 | fos.close(); 59 | } 60 | 61 | // 文件转对象 62 | public static Object readFile2Obj(String filePath) throws IOException, ClassNotFoundException { 63 | FileInputStream fis = new FileInputStream(filePath); 64 | ObjectInputStream ois = new ObjectInputStream(fis); 65 | Object obj = ois.readObject(); 66 | fis.close(); 67 | return obj; 68 | } 69 | 70 | // 文件转对象 71 | public static Object readFile2Obj(File file) throws IOException, ClassNotFoundException { 72 | FileInputStream fis = new FileInputStream(file); 73 | ObjectInputStream ois = new ObjectInputStream(fis); 74 | Object obj = ois.readObject(); 75 | fis.close(); 76 | return obj; 77 | } 78 | 79 | // 检查并更正文件路径 80 | public static String checkFilePath(String path) { 81 | if (CommonUtils.isWindows()) { 82 | return path.replace("/", "\\"); 83 | } else { 84 | return path.replace("\\", "/"); 85 | } 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/web/common/Constants.java: -------------------------------------------------------------------------------- 1 | package com.jmd.web.common; 2 | 3 | public class Constants { 4 | 5 | public final static String WEBSOKET_SESSION_INDEX = "WEBSOKET_SESSION_INDEX"; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/web/common/RESTfulResult.java: -------------------------------------------------------------------------------- 1 | package com.jmd.web.common; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class RESTfulResult { 7 | 8 | private Integer code; 9 | private String message; 10 | private Boolean success; 11 | private T data; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/web/common/WsSendData.java: -------------------------------------------------------------------------------- 1 | package com.jmd.web.common; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class WsSendData { 7 | 8 | private String title; 9 | private String content; 10 | 11 | public WsSendData(String title, String content) { 12 | this.title = title; 13 | this.content = content; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/web/config/WebMvcConfig.java: -------------------------------------------------------------------------------- 1 | package com.jmd.web.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 5 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; 6 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; 7 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 8 | 9 | @EnableWebMvc 10 | @Configuration 11 | public class WebMvcConfig implements WebMvcConfigurer { 12 | 13 | @Override 14 | public void addResourceHandlers(ResourceHandlerRegistry registry) { 15 | registry.addResourceHandler("/web/**").addResourceLocations("classpath:/web/"); 16 | } 17 | 18 | @Override 19 | public void addViewControllers(ViewControllerRegistry registry) { 20 | // registry.addViewController("/index.html").setViewName(""); 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/web/controller/InfoController.kt: -------------------------------------------------------------------------------- 1 | package com.jmd.web.controller 2 | 3 | import com.jmd.ApplicationPort 4 | import com.jmd.web.common.RESTfulResult 5 | import org.springframework.web.bind.annotation.* 6 | 7 | @CrossOrigin 8 | @RestController 9 | @RequestMapping("/info") 10 | class InfoController { 11 | 12 | @RequestMapping(value = ["/getWsPath"], method = [RequestMethod.GET]) 13 | @ResponseBody 14 | fun getWsPath(): RESTfulResult { 15 | val result = RESTfulResult() 16 | result.code = 200 17 | result.message = "ok" 18 | result.success = true 19 | result.data = "ws://localhost:${ApplicationPort.startPort}/websocket/map" 20 | return result 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/web/controller/TileController.kt: -------------------------------------------------------------------------------- 1 | package com.jmd.web.controller 2 | 3 | import com.jmd.util.ImageUtils 4 | import com.jmd.web.service.TileService 5 | import org.springframework.beans.factory.annotation.Autowired 6 | import org.springframework.http.HttpHeaders 7 | import org.springframework.http.HttpStatus 8 | import org.springframework.http.MediaType 9 | import org.springframework.http.ResponseEntity 10 | import org.springframework.web.bind.annotation.* 11 | 12 | @CrossOrigin 13 | @RestController 14 | @RequestMapping("/tile") 15 | class TileController { 16 | 17 | @Autowired 18 | private val tileService: TileService? = null 19 | 20 | @RequestMapping(value = ["/local"], method = [RequestMethod.GET]) 21 | @ResponseBody 22 | fun local(@RequestParam("z") z: Int, @RequestParam("x") x: Int, @RequestParam("y") y: Int): ResponseEntity { 23 | val headers = HttpHeaders() 24 | val bytes = tileService!!.getTileImageByteLocal(z, x, y) 25 | headers.add(HttpHeaders.CONTENT_TYPE, getContentType(bytes)) 26 | return ResponseEntity(bytes, headers, HttpStatus.OK) 27 | } 28 | 29 | @RequestMapping(value = ["/proxy"], method = [RequestMethod.GET]) 30 | @ResponseBody 31 | fun proxy( 32 | @RequestParam("z") z: Int, 33 | @RequestParam("x") x: Int, 34 | @RequestParam("y") y: Int, 35 | @RequestParam("url") url: String? 36 | ): ResponseEntity { 37 | val headers = HttpHeaders() 38 | val bytes = tileService!!.getTileImageByteByProxy(z, x, y, url) 39 | headers.add(HttpHeaders.CONTENT_TYPE, getContentType(bytes)) 40 | return ResponseEntity(bytes, headers, HttpStatus.OK) 41 | } 42 | 43 | private fun getContentType(imageBytes: ByteArray): String? { 44 | val type = ImageUtils.getImageType(imageBytes) ?: return null 45 | return when (type) { 46 | ImageUtils.Type.PNG -> { 47 | MediaType.IMAGE_PNG_VALUE 48 | } 49 | 50 | ImageUtils.Type.JPG -> { 51 | MediaType.IMAGE_JPEG_VALUE 52 | } 53 | 54 | ImageUtils.Type.GIF -> { 55 | MediaType.IMAGE_GIF_VALUE 56 | } 57 | 58 | ImageUtils.Type.WEBP -> { 59 | "image/webp" 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/web/controller/WebSubmitController.kt: -------------------------------------------------------------------------------- 1 | package com.jmd.web.controller 2 | 3 | import com.jmd.model.controller.WebDownloadSubmitVo 4 | import com.jmd.web.common.RESTfulResult 5 | import com.jmd.web.service.WebSubmitService 6 | import org.springframework.beans.factory.annotation.Autowired 7 | import org.springframework.web.bind.annotation.* 8 | 9 | @CrossOrigin 10 | @RestController 11 | @RequestMapping("/submit") 12 | class WebSubmitController { 13 | 14 | @Autowired 15 | private val webSubmitService: WebSubmitService? = null 16 | 17 | @RequestMapping(value = ["/blockDownload"], method = [RequestMethod.POST]) 18 | @ResponseBody 19 | fun blockDownload(@RequestBody vo: WebDownloadSubmitVo?): RESTfulResult<*> { 20 | val result: RESTfulResult<*> = RESTfulResult() 21 | webSubmitService!!.blockDownload(vo) 22 | result.code = 200 23 | result.message = "ok" 24 | result.success = true 25 | return result 26 | } 27 | 28 | @RequestMapping(value = ["worldDownload"], method = [RequestMethod.POST]) 29 | @ResponseBody 30 | fun worldDownload(@RequestBody vo: WebDownloadSubmitVo?): RESTfulResult<*> { 31 | val result: RESTfulResult<*> = RESTfulResult() 32 | webSubmitService!!.worldDownload(vo) 33 | result.code = 200 34 | result.message = "ok" 35 | result.success = true 36 | return result 37 | } 38 | } -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/web/service/TileService.java: -------------------------------------------------------------------------------- 1 | package com.jmd.web.service; 2 | 3 | public interface TileService { 4 | 5 | byte[] getTileImageByteLocal(int z, int x, int y); 6 | 7 | byte[] getTileImageByteByProxy(int z, int x, int y, String url); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/web/service/WebSubmitService.java: -------------------------------------------------------------------------------- 1 | package com.jmd.web.service; 2 | 3 | import com.jmd.model.controller.WebDownloadSubmitVo; 4 | 5 | public interface WebSubmitService { 6 | 7 | void blockDownload(WebDownloadSubmitVo vo); 8 | 9 | void worldDownload(WebDownloadSubmitVo vo); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/web/service/impl/TileServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.jmd.web.service.impl; 2 | 3 | import com.jmd.http.HttpClient; 4 | import com.jmd.model.tile.TileViewParam; 5 | import com.jmd.rx.Topic; 6 | import com.jmd.rx.client.InnerMqClient; 7 | import com.jmd.rx.service.InnerMqService; 8 | import com.jmd.util.CommonUtils; 9 | import com.jmd.util.MyFileUtils; 10 | import com.jmd.util.TaskUtils; 11 | import com.jmd.web.service.TileService; 12 | import jakarta.annotation.PostConstruct; 13 | import jakarta.annotation.PreDestroy; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.stereotype.Service; 16 | 17 | @Service 18 | public class TileServiceImpl implements TileService { 19 | 20 | private final InnerMqService innerMqService = InnerMqService.getInstance(); 21 | private InnerMqClient client; 22 | 23 | @Autowired 24 | private HttpClient http; 25 | 26 | private TileViewParam tileViewParam; 27 | 28 | @PostConstruct 29 | private void init() { 30 | try { 31 | this.subInnerMqMessage(); 32 | } catch (Exception e) { 33 | e.printStackTrace(); 34 | } 35 | } 36 | 37 | @PreDestroy 38 | protected void destroy() { 39 | this.innerMqService.destroyClient(this.client); 40 | } 41 | 42 | private void subInnerMqMessage() throws Exception { 43 | this.client = innerMqService.createClient(); 44 | this.client.sub(Topic.OPEN_TILE_VIEW, (res) -> this.tileViewParam = res); 45 | } 46 | 47 | @Override 48 | public byte[] getTileImageByteLocal(int z, int x, int y) { 49 | if (this.tileViewParam != null && this.tileViewParam.check()) { 50 | var filePath = this.tileViewParam.getPath() + 51 | TaskUtils.getFilePathName(this.tileViewParam.getPathStyle(), this.tileViewParam.getType(), z, x, y); 52 | try { 53 | return MyFileUtils.getFileBytes(filePath); 54 | } catch (Exception e) { 55 | return new byte[0]; 56 | } 57 | } 58 | return new byte[0]; 59 | } 60 | 61 | @Override 62 | public byte[] getTileImageByteByProxy(int z, int x, int y, String url) { 63 | try { 64 | var tileUrl = CommonUtils.getDialectUrl("", url, z, x, y); 65 | return this.http.getFileBytes(tileUrl, HttpClient.HEADERS); 66 | } catch (Exception e) { 67 | return new byte[0]; 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/web/websocket/config/SpringWebSocketConfig.java: -------------------------------------------------------------------------------- 1 | package com.jmd.web.websocket.config; 2 | 3 | import com.jmd.web.websocket.handler.MapWebSocketHandler; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; 7 | import org.springframework.web.socket.config.annotation.EnableWebSocket; 8 | import org.springframework.web.socket.config.annotation.WebSocketConfigurer; 9 | import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; 10 | 11 | @Configuration 12 | @EnableWebSocket 13 | public class SpringWebSocketConfig extends WebMvcConfigurationSupport implements WebSocketConfigurer { 14 | 15 | @Autowired 16 | private MapWebSocketHandler mapWebSocketHandler; 17 | 18 | @Override 19 | public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { 20 | registry.addHandler(mapWebSocketHandler, "/websocket/map") 21 | .addInterceptors(new SpringWebSocketHandlerInterceptor()).setAllowedOrigins("*"); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/web/websocket/config/SpringWebSocketHandlerInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.jmd.web.websocket.config; 2 | 3 | import com.jmd.web.common.Constants; 4 | import jakarta.servlet.http.HttpServletRequest; 5 | import jakarta.servlet.http.HttpServletResponse; 6 | import jakarta.servlet.http.HttpSession; 7 | import org.springframework.http.server.ServerHttpRequest; 8 | import org.springframework.http.server.ServerHttpResponse; 9 | import org.springframework.http.server.ServletServerHttpRequest; 10 | import org.springframework.http.server.ServletServerHttpResponse; 11 | import org.springframework.lang.Nullable; 12 | import org.springframework.web.socket.WebSocketHandler; 13 | import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; 14 | 15 | import java.util.Map; 16 | 17 | public class SpringWebSocketHandlerInterceptor extends HttpSessionHandshakeInterceptor { 18 | 19 | @Override 20 | public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, 21 | Map attributes) throws Exception { 22 | 23 | HttpSession session = getSession(request); 24 | if (null != session && null == session.getAttribute("kickout")) { 25 | String[] uri = request.getURI().toString().split("/"); 26 | String index = uri[uri.length - 1]; 27 | String sessionIndex = Constants.WEBSOKET_SESSION_INDEX + "_" + session.getId() + "_" + index; 28 | attributes.put(Constants.WEBSOKET_SESSION_INDEX, sessionIndex); 29 | } 30 | return super.beforeHandshake(request, response, wsHandler, attributes); 31 | } 32 | 33 | @Override 34 | public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, 35 | Exception exception) { 36 | HttpServletRequest httpRequest = ((ServletServerHttpRequest) request).getServletRequest(); 37 | HttpServletResponse httpResponse = ((ServletServerHttpResponse) response).getServletResponse(); 38 | if (httpRequest.getHeader("sec-websocket-protocol") != null) { 39 | httpResponse.addHeader("sec-websocket-protocol", httpRequest.getHeader("sec-websocket-protocol")); 40 | } 41 | super.afterHandshake(request, response, wsHandler, exception); 42 | } 43 | 44 | @Nullable 45 | private HttpSession getSession(ServerHttpRequest request) { 46 | if (request instanceof ServletServerHttpRequest) { 47 | ServletServerHttpRequest serverRequest = (ServletServerHttpRequest) request; 48 | return serverRequest.getServletRequest().getSession(true); 49 | } 50 | return null; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/web/websocket/handler/MapWebSocketHandler.java: -------------------------------------------------------------------------------- 1 | package com.jmd.web.websocket.handler; 2 | 3 | import com.alibaba.fastjson2.JSON; 4 | import com.alibaba.fastjson2.JSONObject; 5 | import com.jmd.ApplicationSetting; 6 | import com.jmd.common.WsSendTopic; 7 | import com.jmd.web.common.WsSendData; 8 | import com.jmd.web.websocket.handler.base.BaseWebSocketHandler; 9 | import org.springframework.stereotype.Component; 10 | import org.springframework.web.socket.TextMessage; 11 | import org.springframework.web.socket.WebSocketSession; 12 | 13 | import java.util.HashMap; 14 | 15 | @Component 16 | public class MapWebSocketHandler extends BaseWebSocketHandler { 17 | 18 | @Override 19 | public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception { 20 | super.afterConnectionEstablished(webSocketSession); 21 | var addedLayers = ApplicationSetting.getSetting().getAddedLayers(); 22 | var mapConfig = new HashMap<>(); 23 | mapConfig.put("addedLayers", addedLayers); 24 | var data = new WsSendData(WsSendTopic.INIT_MAP_CONFIG, JSON.toJSONString(mapConfig)); 25 | this.send(data); 26 | } 27 | 28 | public void send(WsSendData data) { 29 | for (String key : webSocketSessionMap.keySet()) { 30 | sendMessageToUser(key, new TextMessage(JSON.toJSONString(data))); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Code/src/main/java/com/jmd/web/websocket/handler/base/BaseWebSocketHandler.java: -------------------------------------------------------------------------------- 1 | package com.jmd.web.websocket.handler.base; 2 | 3 | import com.jmd.web.common.Constants; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.web.socket.CloseStatus; 7 | import org.springframework.web.socket.TextMessage; 8 | import org.springframework.web.socket.WebSocketSession; 9 | import org.springframework.web.socket.handler.TextWebSocketHandler; 10 | 11 | import java.io.IOException; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | @Slf4j 16 | public class BaseWebSocketHandler extends TextWebSocketHandler { 17 | 18 | /** hashMap存取websocketSession,键值为HttpSession sessionID */ 19 | public static Map webSocketSessionMap = new HashMap<>(); 20 | 21 | /** onOpen */ 22 | @Override 23 | public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception { 24 | String sessionIndex = (String) webSocketSession.getAttributes().get(Constants.WEBSOKET_SESSION_INDEX); 25 | webSocketSessionMap.put(sessionIndex, webSocketSession); 26 | log.info("Session Index: {} 建立websocket连接成功,当前数量:{}", sessionIndex, webSocketSessionMap.size()); 27 | } 28 | 29 | /** onClose */ 30 | @Override 31 | public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception { 32 | String sessionIndex = (String) webSocketSession.getAttributes().get(Constants.WEBSOKET_SESSION_INDEX); 33 | webSocketSessionMap.remove(sessionIndex); 34 | log.info("Session Index: {} websocket连接关闭", sessionIndex); 35 | } 36 | 37 | /** onMessage */ 38 | @Override 39 | protected void handleTextMessage(WebSocketSession webSocketSession, TextMessage message) throws Exception { 40 | super.handleTextMessage(webSocketSession, message); 41 | } 42 | 43 | /** onError */ 44 | @Override 45 | public void handleTransportError(WebSocketSession webSocketSession, Throwable exception) throws Exception { 46 | if (webSocketSession.isOpen()) { 47 | webSocketSession.close(); 48 | } 49 | String sessionIndex = (String) webSocketSession.getAttributes().get(Constants.WEBSOKET_SESSION_INDEX); 50 | webSocketSessionMap.remove(sessionIndex); 51 | log.info("Session Index: {} websocket连接异常", sessionIndex); 52 | } 53 | 54 | @Override 55 | public boolean supportsPartialMessages() { 56 | return false; 57 | } 58 | 59 | /** websocket发消息给指定用户 */ 60 | public void sendMessageToUser(String sessionKey, TextMessage message) { 61 | WebSocketSession webSocketSession = webSocketSessionMap.get(sessionKey); 62 | if (null != webSocketSession && webSocketSession.isOpen()) { 63 | try { 64 | webSocketSession.sendMessage(message); 65 | } catch (IOException e) { 66 | log.error("WebSocket SendMessage Exception", e); 67 | } 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /Code/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | logging.level.root: info 2 | logging.file.name: ./log/application.log 3 | 4 | setting: 5 | build: 6 | date: 2023-06-28 7 | version: 8 | jdk: JetBrains Runtime 17 9 | jcef: 111 10 | openlayers: 7.3.0 11 | angular: 16.0.4 12 | opencv: 4.7.0 13 | git: 14 | address: https://gitee.com/CrimsonHu/java_map_download 15 | web: 16 | prod: true 17 | 18 | spring: 19 | datasource: 20 | driver-class-name: org.sqlite.JDBC 21 | url: jdbc:sqlite::resource:db.sqlite3 22 | 23 | mybatis: 24 | mapper-locations: classpath*:com/jmd/db/dao/mapper/*Mapper.xml 25 | 26 | okhttp: 27 | connect-timeout: 7500 28 | read-timeout: 7500 29 | write-timeout: 7500 30 | max-idle-connections: 1024 31 | keep-alive-duration: 5000 32 | 33 | tile: 34 | block-divide: 289 35 | 36 | download: 37 | retry: 1 38 | 39 | pool: 40 | thread: 41 | tile-calculation: 12 42 | tile-download: 256 -------------------------------------------------------------------------------- /Code/src/test/java/com/jmd/ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.jmd; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ApplicationTests { 8 | 9 | @Test 10 | public void test() { 11 | 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Other/image/frame/add-tile-frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/add-tile-frame.png -------------------------------------------------------------------------------- /Other/image/frame/add-tile-setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/add-tile-setting.png -------------------------------------------------------------------------------- /Other/image/frame/download-frame-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/download-frame-1.png -------------------------------------------------------------------------------- /Other/image/frame/download-frame-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/download-frame-2.png -------------------------------------------------------------------------------- /Other/image/frame/float-window-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/float-window-1.png -------------------------------------------------------------------------------- /Other/image/frame/float-window-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/float-window-2.png -------------------------------------------------------------------------------- /Other/image/frame/main-frame-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/main-frame-1.png -------------------------------------------------------------------------------- /Other/image/frame/main-frame-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/main-frame-2.png -------------------------------------------------------------------------------- /Other/image/frame/main-frame-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/main-frame-3.png -------------------------------------------------------------------------------- /Other/image/frame/proxy-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/proxy-1.png -------------------------------------------------------------------------------- /Other/image/frame/proxy-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/proxy-2.png -------------------------------------------------------------------------------- /Other/image/frame/theme-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/theme-1.png -------------------------------------------------------------------------------- /Other/image/frame/theme-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/theme-2.png -------------------------------------------------------------------------------- /Other/image/frame/theme-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/theme-3.png -------------------------------------------------------------------------------- /Other/image/frame/theme-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/theme-4.png -------------------------------------------------------------------------------- /Other/image/frame/theme-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/theme-5.png -------------------------------------------------------------------------------- /Other/image/frame/theme-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/theme-6.png -------------------------------------------------------------------------------- /Other/image/frame/theme-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/theme-7.png -------------------------------------------------------------------------------- /Other/image/frame/theme-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/theme-8.png -------------------------------------------------------------------------------- /Other/image/frame/tile-view-browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/tile-view-browser.png -------------------------------------------------------------------------------- /Other/image/frame/tile-view-frame-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/tile-view-frame-1.png -------------------------------------------------------------------------------- /Other/image/frame/tile-view-setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/frame/tile-view-setting.png -------------------------------------------------------------------------------- /Other/image/other/opencv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/other/opencv.png -------------------------------------------------------------------------------- /Other/image/other/sqlite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/other/sqlite.png -------------------------------------------------------------------------------- /Other/image/other/web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/other/web.png -------------------------------------------------------------------------------- /Other/image/tile/163712_032f9f19_1403243.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/tile/163712_032f9f19_1403243.webp -------------------------------------------------------------------------------- /Other/image/tile/184433_266b9408_1403243.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/tile/184433_266b9408_1403243.webp -------------------------------------------------------------------------------- /Other/image/tile/191831_0fe37c36_1403243.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/tile/191831_0fe37c36_1403243.webp -------------------------------------------------------------------------------- /Other/image/tile/191841_58a9107e_1403243.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/tile/191841_58a9107e_1403243.webp -------------------------------------------------------------------------------- /Other/image/tile/192008_a3e72cda_1403243.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/tile/192008_a3e72cda_1403243.webp -------------------------------------------------------------------------------- /Other/image/tile/194201_51cbcc76_1403243.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/tile/194201_51cbcc76_1403243.webp -------------------------------------------------------------------------------- /Other/image/tile/200828_c79e7461_1403243.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/tile/200828_c79e7461_1403243.webp -------------------------------------------------------------------------------- /Other/image/tile/201358_ee4b9a82_1403243.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/tile/201358_ee4b9a82_1403243.webp -------------------------------------------------------------------------------- /Other/image/tile/201415_178ebde6_1403243.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/tile/201415_178ebde6_1403243.webp -------------------------------------------------------------------------------- /Other/image/tile/235757_070c3fc7_1403243.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/tile/235757_070c3fc7_1403243.webp -------------------------------------------------------------------------------- /Other/image/tile/AQGA19U6SF0O7TQJGZGR8Q.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/tile/AQGA19U6SF0O7TQJGZGR8Q.png -------------------------------------------------------------------------------- /Other/image/tile/YL2S6HW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/tile/YL2S6HW.png -------------------------------------------------------------------------------- /Other/image/tile/ZWGLCVCLS2V57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Other/image/tile/ZWGLCVCLS2V57.png -------------------------------------------------------------------------------- /Web/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | -------------------------------------------------------------------------------- /Web/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] # 表示所有文件适用 6 | charset = utf-8 # 设置文件字符集为 utf-8 7 | indent_style = tab # 缩进风格(tab | space) 8 | indent_size = 4 # 缩进大小 9 | end_of_line = lf # 控制换行类型(lf | cr | crlf) 10 | trim_trailing_whitespace = true # 去除行首的任意空白字符 11 | insert_final_newline = true # 始终在文件末尾插入一个新行 12 | 13 | [*.{js,ts}] 14 | ij_javascript_spaces_within_imports = true 15 | ij_javascript_spaces_within_object_literal_braces = true 16 | ij_javascript_object_literal_wrap = off 17 | ij_typescript_spaces_within_imports = true 18 | ij_typescript_spaces_within_object_literal_braces = true 19 | ij_typescript_spaces_within_object_type_braces = true 20 | ij_typescript_object_literal_wrap = off 21 | 22 | [*.json] 23 | indent_size = 2 24 | 25 | -------------------------------------------------------------------------------- /Web/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # Visual Studio Code 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # Miscellaneous 32 | /.angular/cache 33 | .sass-cache/ 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | testem.log 38 | /typings 39 | 40 | # System files 41 | .DS_Store 42 | Thumbs.db 43 | 44 | /package-lock.json 45 | -------------------------------------------------------------------------------- /Web/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "Web": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "scss" 11 | } 12 | }, 13 | "root": "", 14 | "sourceRoot": "src", 15 | "prefix": "app", 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:browser-esbuild", 19 | "options": { 20 | "outputPath": "dist/web", 21 | "index": "src/index.html", 22 | "main": "src/main.ts", 23 | "polyfills": [ 24 | "zone.js" 25 | ], 26 | "tsConfig": "tsconfig.app.json", 27 | "inlineStyleLanguage": "scss", 28 | "assets": [ 29 | "src/favicon.ico", 30 | "src/assets" 31 | ], 32 | "styles": [ 33 | "@angular/material/prebuilt-themes/indigo-pink.css", 34 | "src/styles.scss", 35 | "src/assets/lib/openlayers/ol.css" 36 | ], 37 | "scripts": [ 38 | "src/assets/lib/elm-pep/elm-pep.js", 39 | "src/assets/lib/element-resize-detector/element-resize-detector.js", 40 | "src/assets/lib/openlayers/ol.js", 41 | "src/assets/lib/openlayers/mapbox-streets-v6-style.js" 42 | ] 43 | }, 44 | "configurations": { 45 | "production": { 46 | "budgets": [ 47 | { 48 | "type": "initial", 49 | "maximumWarning": "500kb", 50 | "maximumError": "1mb" 51 | }, 52 | { 53 | "type": "anyComponentStyle", 54 | "maximumWarning": "2kb", 55 | "maximumError": "4kb" 56 | } 57 | ], 58 | "outputHashing": "all" 59 | }, 60 | "development": { 61 | "buildOptimizer": false, 62 | "optimization": false, 63 | "vendorChunk": true, 64 | "extractLicenses": false, 65 | "sourceMap": true, 66 | "namedChunks": true 67 | } 68 | }, 69 | "defaultConfiguration": "production" 70 | }, 71 | "serve": { 72 | "builder": "@angular-devkit/build-angular:dev-server", 73 | "configurations": { 74 | "production": { 75 | "browserTarget": "Web:build:production" 76 | }, 77 | "development": { 78 | "browserTarget": "Web:build:development" 79 | } 80 | }, 81 | "defaultConfiguration": "development" 82 | }, 83 | "extract-i18n": { 84 | "builder": "@angular-devkit/build-angular:extract-i18n", 85 | "options": { 86 | "browserTarget": "Web:build" 87 | } 88 | }, 89 | "test": { 90 | "builder": "@angular-devkit/build-angular:karma", 91 | "options": { 92 | "polyfills": [ 93 | "zone.js", 94 | "zone.js/testing" 95 | ], 96 | "tsConfig": "tsconfig.spec.json", 97 | "inlineStyleLanguage": "scss", 98 | "assets": [ 99 | "src/favicon.ico", 100 | "src/assets" 101 | ], 102 | "styles": [ 103 | "src/styles.scss" 104 | ], 105 | "scripts": [] 106 | } 107 | } 108 | } 109 | } 110 | }, 111 | "cli": { 112 | "analytics": "e9b7c772-8d1c-403f-abe0-5628fc0c90ff" 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve --port 4500", 7 | "build": "ng build --base-href /web/index.html --configuration production --build-optimizer" 8 | }, 9 | "private": true, 10 | "dependencies": { 11 | "@angular/animations": "^16.0.3", 12 | "@angular/cdk": "^16.0.3", 13 | "@angular/common": "^16.0.3", 14 | "@angular/compiler": "^16.0.3", 15 | "@angular/core": "^16.0.3", 16 | "@angular/forms": "^16.0.3", 17 | "@angular/material": "^16.0.3", 18 | "@angular/platform-browser": "^16.0.3", 19 | "@angular/platform-browser-dynamic": "^16.0.3", 20 | "@angular/router": "^16.0.3", 21 | "lodash-es": "^4.17.21", 22 | "rxjs": "~7.8.0", 23 | "tslib": "^2.5.0", 24 | "zone.js": "~0.13.0" 25 | }, 26 | "devDependencies": { 27 | "@angular-devkit/build-angular": "^16.0.3", 28 | "@angular/cli": "^16.0.3", 29 | "@angular/compiler-cli": "^16.0.3", 30 | "@types/jasmine": "~4.3.1", 31 | "@types/lodash-es": "^4.17.7", 32 | "@types/node": "18.15.3", 33 | "jasmine-core": "~4.6.0", 34 | "karma": "~6.4.1", 35 | "karma-chrome-launcher": "~3.1.1", 36 | "karma-coverage": "~2.2.0", 37 | "karma-jasmine": "~5.1.0", 38 | "karma-jasmine-html-reporter": "~2.0.0", 39 | "typescript": "~5.0.2" 40 | } 41 | } -------------------------------------------------------------------------------- /Web/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | const routes: Routes = [ 5 | { // 主页 6 | path: '', 7 | loadChildren: () => import('./view/page/index.page-module').then(mod => mod.IndexPageModule) 8 | } 9 | ]; 10 | 11 | @NgModule({ 12 | imports: [RouterModule.forRoot(routes, { useHash: true })], 13 | exports: [RouterModule] 14 | }) 15 | export class AppRoutingModule { 16 | } 17 | -------------------------------------------------------------------------------- /Web/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Web/src/app/app.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Web/src/app/app.component.scss -------------------------------------------------------------------------------- /Web/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.scss'] 7 | }) 8 | export class AppComponent { 9 | } 10 | -------------------------------------------------------------------------------- /Web/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 4 | import { HttpClientModule } from '@angular/common/http'; 5 | import { AppComponent } from './app.component'; 6 | import { AppRoutingModule } from './app-routing.module'; 7 | import { HttpClientService } from './http/http-client.service'; 8 | import { HttpInterceptorProvider } from './http/http-interceptor.provider'; 9 | import { InnerMqService } from "./rx/inner-mq/service/inner-mq.service"; 10 | 11 | 12 | @NgModule({ 13 | declarations: [ 14 | AppComponent 15 | ], 16 | imports: [ 17 | BrowserModule, 18 | BrowserAnimationsModule, 19 | HttpClientModule, 20 | AppRoutingModule, 21 | ], 22 | providers: [ 23 | HttpClientService, 24 | HttpInterceptorProvider, 25 | InnerMqService, 26 | ], 27 | bootstrap: [AppComponent] 28 | }) 29 | export class AppModule { 30 | } 31 | -------------------------------------------------------------------------------- /Web/src/app/common/common-var.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT_LAYER_NAME = 'AMap-Normal'; 2 | export const TIAN_MAP_KEY = '81dd3e1715be9d296f1a9f2b0c0196aa'; 3 | -------------------------------------------------------------------------------- /Web/src/app/connection/onmassage/map-message.connection.ts: -------------------------------------------------------------------------------- 1 | import { WebSocketConfigOption } from '../websocket/WebSocketConfigOption'; 2 | import { ReconnectableWebSocket } from '../websocket/ReconnectableWebSocket'; 3 | import { InnerMqService } from "../../rx/inner-mq/service/inner-mq.service"; 4 | 5 | export class MapMessageConnection { 6 | 7 | private ws!: ReconnectableWebSocket; 8 | 9 | constructor( 10 | private path: string, 11 | private innerMqService: InnerMqService, 12 | ) { 13 | this.connection(); 14 | } 15 | 16 | /** 连接 */ 17 | private connection(): void { 18 | let wsConfig: WebSocketConfigOption = { 19 | url: this.path, 20 | onopen: () => { 21 | }, 22 | onerror: () => { 23 | }, 24 | onmessage: (msg: any) => { 25 | if (msg.data && msg.data !== '') { 26 | let data = JSON.parse(msg.data); 27 | this.innerMqService.pub(data.title, data.content); 28 | } 29 | } 30 | } 31 | this.ws = new ReconnectableWebSocket(wsConfig); 32 | } 33 | 34 | /** 断开连接 */ 35 | public disConnection(): void { 36 | this.ws.close(); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Web/src/app/connection/websocket/ReconnectableWebSocket.ts: -------------------------------------------------------------------------------- 1 | import { WebSocketConfigOption } from './WebSocketConfigOption'; 2 | 3 | export class ReconnectableWebSocket { 4 | 5 | private ws!: WebSocket; // ws实例 6 | private opt: WebSocketConfigOption; // ws配置项 7 | private lockReconnect: boolean = false; // 避免ws重复连接 8 | private isClosingWindow: boolean = false; 9 | private reconnectTimeout: any; 10 | private heartSendInterval: any; 11 | 12 | constructor(option: WebSocketConfigOption) { 13 | if (null === option.url || '' === option.url) { 14 | throw ('url不能为空'); 15 | } 16 | this.opt = option; 17 | this.initWebSocket(); 18 | } 19 | 20 | private initWebSocket() { 21 | if (null == this.opt.secWebSocketProtocol) { 22 | this.ws = new WebSocket(this.opt.url); 23 | } else if (this.opt.secWebSocketProtocol.length == 0) { 24 | this.ws = new WebSocket(this.opt.url); 25 | } else { 26 | this.ws = new WebSocket(this.opt.url, this.opt.secWebSocketProtocol); 27 | } 28 | this.initEventHandle(); 29 | window.onbeforeunload = () => { 30 | this.isClosingWindow = true; 31 | this.ws.close(); // 当窗口关闭时,主动去关闭websocket连接。 32 | } 33 | } 34 | 35 | private initEventHandle() { 36 | this.ws.onclose = () => { 37 | console.log('ws连接关闭!' + this.opt.url); 38 | this.opt.onclose && this.opt.onclose(); 39 | this.heartCheckStop(); 40 | if (!this.isClosingWindow) { 41 | this.reconnect(); 42 | } 43 | } 44 | this.ws.onerror = () => { 45 | console.log('ws连接错误!' + this.opt.url); 46 | this.opt.onerror && this.opt.onerror(); 47 | this.heartCheckStop(); 48 | if (!this.isClosingWindow) { 49 | this.reconnect(); 50 | } 51 | } 52 | this.ws.onopen = () => { 53 | console.log('ws连接成功!' + this.opt.url); 54 | this.opt.onopen && this.opt.onopen(); 55 | this.heartCheckStart(); 56 | } 57 | this.ws.onmessage = (event: any) => { 58 | this.opt.onmessage && this.opt.onmessage(event); 59 | } 60 | } 61 | 62 | /** 重连 */ 63 | private reconnect() { 64 | if (this.lockReconnect) { 65 | return; 66 | } 67 | this.lockReconnect = true; 68 | this.reconnectTimeout = setTimeout(() => { 69 | this.initWebSocket(); 70 | this.lockReconnect = false; 71 | }, 2000); 72 | } 73 | 74 | /** 关闭重连 */ 75 | private reconnectStop(): void { 76 | clearTimeout(this.reconnectTimeout); 77 | } 78 | 79 | /** 开启心跳包保持连接 */ 80 | private heartCheckStart(): void { 81 | this.ws.send('heartCheck'); 82 | this.heartSendInterval = setInterval(() => { 83 | this.ws.send('heartCheck'); 84 | }, 5 * 60 * 1000); 85 | } 86 | 87 | /** 关闭心跳包 */ 88 | private heartCheckStop(): void { 89 | clearInterval(this.heartSendInterval); 90 | } 91 | 92 | /** 主动关闭连接 */ 93 | public close(): void { 94 | this.reconnectStop(); 95 | this.heartCheckStop(); 96 | this.isClosingWindow = true; 97 | this.ws.close(); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /Web/src/app/connection/websocket/WebSocketConfigOption.ts: -------------------------------------------------------------------------------- 1 | export type WebSocketConfigOption = { 2 | 3 | url: string; 4 | secWebSocketProtocol?: Array; 5 | onopen?: () => void; 6 | onmessage?: (msg: any) => void; 7 | onerror?: () => void; 8 | onclose?: () => void; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /Web/src/app/http/http-client.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { HttpParamsEntity } from './http-params.entity'; 4 | import { HttpMethod } from './http-method'; 5 | import { lastValueFrom } from 'rxjs'; 6 | 7 | @Injectable() 8 | export class HttpClientService { 9 | 10 | constructor( 11 | private http: HttpClient, 12 | ) { 13 | } 14 | 15 | public request(params: HttpParamsEntity): any { 16 | switch (params.method) { 17 | case HttpMethod.GET: 18 | return this.get(params.url, params.data === null ? {} : params.data); 19 | case HttpMethod.POST: 20 | return this.post(params.url, params.data === null ? {} : params.data); 21 | default: 22 | break; 23 | } 24 | } 25 | 26 | private get(url: string, params: any): Promise { 27 | return lastValueFrom(this.http.get(url, { 28 | params: params, 29 | responseType: 'json' 30 | })); 31 | } 32 | 33 | private post(url: string, params: any): Promise { 34 | return lastValueFrom(this.http.post(url, params, { 35 | responseType: 'json' 36 | })); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Web/src/app/http/http-interceptor.provider.ts: -------------------------------------------------------------------------------- 1 | import { HTTP_INTERCEPTORS } from '@angular/common/http'; 2 | 3 | import { HttpInterceptorService } from './http-interceptor.service'; 4 | 5 | /** Http interceptor providers in outside-in order */ 6 | export const HttpInterceptorProvider = [ 7 | { provide: HTTP_INTERCEPTORS, useClass: HttpInterceptorService, multi: true } 8 | ]; 9 | 10 | /* 11 | Copyright 2017-2018 Google Inc. All Rights Reserved. 12 | Use of this source code is governed by an MIT-style license that 13 | can be found in the LICENSE file at http://angular.io/license 14 | */ -------------------------------------------------------------------------------- /Web/src/app/http/http-interceptor.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse } from '@angular/common/http'; 3 | import { throwError } from 'rxjs'; 4 | import { catchError, retry } from 'rxjs/operators'; 5 | import { environment } from 'src/environments/environment'; 6 | 7 | @Injectable() 8 | export class HttpInterceptorService implements HttpInterceptor { 9 | 10 | private readonly production: boolean = environment.production; 11 | 12 | constructor() { 13 | } 14 | 15 | intercept(req: HttpRequest, next: HttpHandler) { 16 | let url; 17 | if (this.production) { 18 | url = `http://localhost:${window.location.port}${req.url}`; 19 | } else { 20 | url = `http://localhost:26737${req.url}`; 21 | } 22 | // 设置请求头 23 | let newReq = req.clone({ 24 | url: url, 25 | }); 26 | // send cloned request with header to the next handler. 27 | return next.handle(newReq).pipe( 28 | retry(3), 29 | catchError(this.handleError) 30 | ); 31 | } 32 | 33 | private handleError(error: HttpErrorResponse) { 34 | console.error(`Backend returned code ${error.status},body was: `, error.error); 35 | // return an observable with a user-facing error message 36 | return throwError('Something bad happened; please try again later.'); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Web/src/app/http/http-method.ts: -------------------------------------------------------------------------------- 1 | export enum HttpMethod { 2 | 3 | GET, 4 | POST, 5 | 6 | } 7 | -------------------------------------------------------------------------------- /Web/src/app/http/http-params.entity.ts: -------------------------------------------------------------------------------- 1 | import { HttpMethod } from 'src/app/http/http-method'; 2 | 3 | export class HttpParamsEntity { 4 | 5 | method: HttpMethod; 6 | url: string; 7 | data: any; 8 | 9 | constructor(method: HttpMethod, url: string, data: any) { 10 | this.method = method; 11 | this.url = url; 12 | this.data = data; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Web/src/app/http/restful-result.type.ts: -------------------------------------------------------------------------------- 1 | export type RESTfulResult = { 2 | 3 | code: number, 4 | message: string, 5 | success: boolean, 6 | data: any, 7 | 8 | } 9 | -------------------------------------------------------------------------------- /Web/src/app/map/draw/map-draw.ts: -------------------------------------------------------------------------------- 1 | import { polygonFillColor, polygonStrokeColor } from '../map-base'; 2 | import { Point } from "../entity/Point"; 3 | 4 | declare var ol: any; 5 | 6 | export class MapDraw { 7 | 8 | /** 新建多边形Feature */ 9 | public static createPolygonFeature(points: Array): any { 10 | let pts = []; 11 | for (let i = 0; i < points.length; i++) { 12 | pts.push(ol.proj.fromLonLat([points[i].lng, points[i].lat])); 13 | } 14 | let polygon = new ol.geom.Polygon([pts]); 15 | let feature = new ol.Feature({ geometry: polygon }); 16 | let style = new ol.style.Style({ 17 | stroke: new ol.style.Stroke({ 18 | color: polygonStrokeColor, 19 | width: 3 20 | }), 21 | fill: new ol.style.Fill({ 22 | color: polygonFillColor, 23 | }), 24 | }); 25 | feature.setStyle(style); 26 | return feature; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Web/src/app/map/entity/Point.ts: -------------------------------------------------------------------------------- 1 | export class Point { 2 | 3 | lng: number; 4 | lat: number; 5 | 6 | constructor(lng: number, lat: number) { 7 | this.lng = lng; 8 | this.lat = lat; 9 | } 10 | 11 | public equals(p: Point) { 12 | return this.lng == p.lng && this.lat == p.lat; 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /Web/src/app/map/entity/PointEN.ts: -------------------------------------------------------------------------------- 1 | export class PointEN { 2 | 3 | lng: string; 4 | lat: string; 5 | 6 | constructor(lng: string, lat: string) { 7 | this.lng = lng; 8 | this.lat = lat; 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /Web/src/app/map/entity/PointENObj.ts: -------------------------------------------------------------------------------- 1 | export class PointENObj { 2 | 3 | lng: { 4 | h: number, 5 | m: number, 6 | s: number, 7 | }; 8 | lat: { 9 | h: number, 10 | m: number, 11 | s: number, 12 | }; 13 | 14 | constructor(lng: { h: number, m: number, s: number }, lat: { h: number, m: number, s: number }) { 15 | this.lng = { 16 | h: lng.h, 17 | m: lng.m, 18 | s: lng.s, 19 | }; 20 | this.lat = { 21 | h: lat.h, 22 | m: lat.m, 23 | s: lat.s, 24 | }; 25 | } 26 | 27 | valid(): boolean { 28 | let isNotNull = ( 29 | this.lng.h != null && 30 | this.lng.m != null && 31 | this.lng.s != null && 32 | this.lat.h != null && 33 | this.lat.m != null && 34 | this.lat.s != null 35 | ); 36 | if (!isNotNull) { 37 | return false; 38 | } 39 | return ( 40 | this.lng.h > -180 && this.lng.h < 180 && 41 | this.lng.m >= 0 && this.lng.m < 60 && 42 | this.lng.s >= 0 && this.lng.s < 60 && 43 | this.lat.h > -90 && this.lat.h < 90 && 44 | this.lat.m >= 0 && this.lat.m < 60 && 45 | this.lat.s >= 0 && this.lat.s < 60 46 | ); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /Web/src/app/map/map-base-simple.ts: -------------------------------------------------------------------------------- 1 | declare const elementResizeDetectorMaker: any; 2 | declare const ol: any; 3 | 4 | export class MapBaseSimple { 5 | 6 | protected mapObj: any; 7 | public getOlMap = () => this.mapObj; 8 | 9 | private gridLayer: any; 10 | 11 | constructor( 12 | private dom: HTMLDivElement, 13 | private config: { tileUrl: string }, 14 | private callback?: { onFinish?: Function, onResize?: Function }, 15 | ) { 16 | this.initMap(config, callback).then((e) => { 17 | callback?.onFinish && callback?.onFinish(e); 18 | }); 19 | } 20 | 21 | /** 生成地图 */ 22 | private initMap( 23 | config: { tileUrl: string }, 24 | callback?: { onResize?: Function }, 25 | ): Promise { 26 | let mapLayers = []; 27 | // XYZ 28 | let tileLayer = new ol.layer.Tile({ 29 | source: new ol.source.XYZ({ 30 | url: config.tileUrl, 31 | }), 32 | zIndex: 0, 33 | }); 34 | mapLayers.push(tileLayer); 35 | // 网格 36 | let gridLayer = new ol.layer.Tile({ 37 | source: new ol.source.TileDebug(), 38 | visible: true, 39 | zIndex: 50 40 | }); 41 | mapLayers.push(gridLayer); 42 | this.gridLayer = gridLayer; 43 | /** 实例化地图 */ 44 | this.mapObj = new ol.Map({ 45 | target: this.dom, 46 | layers: mapLayers, 47 | view: new ol.View({ 48 | projection: 'EPSG:3857', 49 | center: ol.proj.fromLonLat([105.203317, 37.506176]), 50 | zoom: 4, 51 | maxZoom: 21, 52 | minZoom: 0 53 | }), 54 | interactions: [ 55 | new ol.interaction.DragPan(), 56 | new ol.interaction.PinchZoom(), 57 | new ol.interaction.KeyboardPan(), 58 | new ol.interaction.KeyboardZoom(), 59 | new ol.interaction.MouseWheelZoom(), 60 | new ol.interaction.DragZoom(), 61 | ], 62 | controls: [ 63 | new ol.control.Zoom(), 64 | new ol.control.ScaleLine(), 65 | ] 66 | }); 67 | // 尺寸自适应 68 | elementResizeDetectorMaker().listenTo(this.dom, (e: HTMLElement) => { 69 | setTimeout(() => { 70 | this.mapObj?.setSize([e.offsetWidth, e.offsetHeight]); 71 | this.mapObj?.getView().setViewportSize([e.offsetWidth, e.offsetHeight]); 72 | callback?.onResize && callback?.onResize(e); 73 | }); 74 | }); 75 | // 异步返回 76 | return new Promise((resolve) => { 77 | setTimeout(() => { 78 | resolve({ 79 | success: true, 80 | msg: `地图加载完成` 81 | }); 82 | }); 83 | }); 84 | } 85 | 86 | /** 销毁地图 */ 87 | public destroyMap(): void { 88 | elementResizeDetectorMaker().uninstall(this.dom); 89 | } 90 | 91 | /** 显示网格 */ 92 | showGrid(): void { 93 | this.gridLayer && this.gridLayer.setVisible(true); 94 | } 95 | 96 | /** 关闭网格 */ 97 | closeGrid(): void { 98 | this.gridLayer && this.gridLayer.setVisible(false); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /Web/src/app/map/map-config-option.ts: -------------------------------------------------------------------------------- 1 | export type MapConfigOption = { 2 | 3 | layer: string; 4 | grid: boolean; 5 | key: { 6 | tian: string; 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /Web/src/app/map/source/amap-source.ts: -------------------------------------------------------------------------------- 1 | declare const ol: any; 2 | 3 | export class AmapSource { 4 | 5 | AMapNormal_Name: string; 6 | AMapNormal_Source: Array; 7 | 8 | AMapNormalNone_Name: string; 9 | AMapNormalNone_Source: Array; 10 | 11 | AMapSatelliteNone_Name: string; 12 | AMapSatelliteNone_Source: Array; 13 | 14 | AMapStreet_Name: string; 15 | AMapStreet_Source: Array; 16 | 17 | AMapStreetNone_Name: string; 18 | AMapStreetNone_Source: Array; 19 | 20 | 21 | constructor() { 22 | // 高德地图-普通图-带标注 23 | const AMapNormal_URL = 'https://webrd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=8'; 24 | this.AMapNormal_Name = 'AMap-Normal'; 25 | this.AMapNormal_Source = [ 26 | { 27 | name: 'Normal', type: 'XYZ_URL', support: true, 28 | source: new ol.source.XYZ({ url: AMapNormal_URL }), 29 | url: AMapNormal_URL, 30 | coordinateType: 'gcj02', 31 | }, 32 | ]; 33 | // 高德地图-普通图-无标注 34 | const AMapNormalNone_URL = 'https://webrd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=8<ype=11'; 35 | this.AMapNormalNone_Name = 'AMap-Normal-None'; 36 | this.AMapNormalNone_Source = [ 37 | { 38 | name: 'Normal-None', type: 'XYZ_URL', support: true, 39 | source: new ol.source.XYZ({ url: AMapNormalNone_URL }), 40 | url: AMapNormalNone_URL, 41 | coordinateType: 'gcj02', 42 | }, 43 | ]; 44 | // 高德地图-影像图-无标注 45 | const AMapSatelliteNone_URL = 'https://webst0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=6'; 46 | this.AMapSatelliteNone_Name = 'AMap-Satellite-None'; 47 | this.AMapSatelliteNone_Source = [ 48 | { 49 | name: 'Satellite-None', type: 'XYZ_URL', support: true, 50 | source: new ol.source.XYZ({ url: AMapSatelliteNone_URL }), 51 | url: AMapSatelliteNone_URL, 52 | coordinateType: 'gcj02', 53 | }, 54 | ]; 55 | // 高德地图-路网图-带标注 56 | const AMapStreet_URL = 'https://webst0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=8'; 57 | this.AMapStreet_Name = 'AMap-Street'; 58 | this.AMapStreet_Source = [ 59 | { 60 | name: 'Street', type: 'XYZ_URL', support: true, 61 | source: new ol.source.XYZ({ url: AMapStreet_URL }), 62 | url: AMapStreet_URL, 63 | coordinateType: 'gcj02', 64 | }, 65 | ]; 66 | // 高德地图-路网图-无标注 67 | const AMapStreetNone_URL = 'https://webst0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=8<ype=11'; 68 | this.AMapStreetNone_Name = 'AMap-Street-None'; 69 | this.AMapStreetNone_Source = [ 70 | { 71 | name: 'Street-None', type: 'XYZ_URL', support: true, 72 | source: new ol.source.XYZ({ url: AMapStreetNone_URL }), 73 | url: AMapStreetNone_URL, 74 | coordinateType: 'gcj02', 75 | }, 76 | ]; 77 | } 78 | 79 | } 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /Web/src/app/map/source/baidu-source.ts: -------------------------------------------------------------------------------- 1 | declare const ol: any; 2 | 3 | export class BaiduSource { 4 | 5 | BaiduNormal_Name: string; 6 | BaiduNormal_Source: Array; 7 | 8 | constructor() { 9 | const bdResolutions = []; 10 | for (let i = 0; i < 19; i++) { 11 | bdResolutions[i] = Math.pow(2, 18 - i); 12 | } 13 | const bdTilegrid = new ol.tilegrid.TileGrid({ 14 | origin: [0, 0], 15 | resolutions: bdResolutions 16 | }); 17 | // 百度地图-普通图-带标注 18 | this.BaiduNormal_Name = 'Baidu-Normal'; 19 | this.BaiduNormal_Source = [ 20 | { 21 | name: 'Normal', type: 'TILE_FUNC', support: false, 22 | source: new ol.source.TileImage({ 23 | projection: 'EPSG:3857', 24 | tileGrid: bdTilegrid, 25 | tileUrlFunction: (tileCoord: any, pixelRatio: any, proj: any) => { 26 | if (!tileCoord) { 27 | return ''; 28 | } 29 | let z = String(tileCoord[0]); 30 | let x = String(tileCoord[1]); 31 | let y = String(-tileCoord[2] - 1); //y坐标变成相反数 32 | if (Number(x) < 0) { 33 | x = 'M' + (-Number(x)); 34 | } 35 | if (Number(y) < 0) { 36 | y = 'M' + (-Number(y)); 37 | } 38 | return 'http://online1.map.bdimg.com/onlinelabel/?qt=tile&x=' + x + '&y=' + y + '&z=' + z + '&styles=pl&scaler=1&p=1' 39 | } 40 | }), 41 | }, 42 | ]; 43 | } 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Web/src/app/map/source/google-source.ts: -------------------------------------------------------------------------------- 1 | declare const ol: any; 2 | 3 | export class GoogleSource { 4 | 5 | GoogleNormal_Name: string; 6 | GoogleNormal_Source: Array; 7 | 8 | GoogleTerrain_Name: string; 9 | GoogleTerrain_Source: Array; 10 | 11 | GoogleSatellite_Name: string; 12 | GoogleSatellite_Source: Array; 13 | 14 | GoogleSatelliteNone_Name: string; 15 | GoogleSatelliteNone_Source: Array; 16 | 17 | GoogleStreet_Name: string; 18 | GoogleStreet_Source: Array; 19 | 20 | constructor() { 21 | // 谷歌地图-普通图-带标注 22 | const GoogleNormal_URL = 'https://mt{1-3}.google.com/maps/vt?lyrs=m%40781&hl=zh-CN&gl=CN&x={x}&y={y}&z={z}'; 23 | this.GoogleNormal_Name = 'Google-Normal'; 24 | this.GoogleNormal_Source = [ 25 | { 26 | name: 'Normal', type: 'XYZ_URL', support: true, 27 | source: new ol.source.XYZ({ url: GoogleNormal_URL }), 28 | url: GoogleNormal_URL, 29 | coordinateType: 'gcj02', 30 | }, 31 | ]; 32 | // 谷歌地图-地形图-带标注 33 | const GoogleTerrain_URL = 'https://mt{1-3}.google.com/maps/vt?lyrs=p%40781&hl=zh-CN&gl=CN&x={x}&y={y}&z={z}'; 34 | this.GoogleTerrain_Name = 'Google-Terrain'; 35 | this.GoogleTerrain_Source = [ 36 | { 37 | name: 'Terrain', type: 'XYZ_URL', support: true, 38 | source: new ol.source.XYZ({ url: GoogleTerrain_URL }), 39 | url: GoogleTerrain_URL, 40 | coordinateType: 'gcj02', 41 | }, 42 | ]; 43 | // 谷歌地图-影像图-带标注 44 | const GoogleSatellite_URL = 'https://mt{1-3}.google.com/maps/vt?lyrs=y%40781&hl=zh-CN&gl=CN&x={x}&y={y}&z={z}'; 45 | this.GoogleSatellite_Name = 'Google-Satellite'; 46 | this.GoogleSatellite_Source = [ 47 | { 48 | name: 'Satellite', type: 'XYZ_URL', support: true, 49 | source: new ol.source.XYZ({ url: GoogleSatellite_URL }), 50 | url: GoogleSatellite_URL, 51 | coordinateType: 'gcj02', 52 | } 53 | ]; 54 | // 谷歌地图-影像图-无标注 55 | const GoogleSatelliteNone_URL = 'https://mt{1-3}.google.com/maps/vt?lyrs=s%40781&hl=zh-CN&gl=CN&x={x}&y={y}&z={z}'; 56 | this.GoogleSatelliteNone_Name = 'Google-Satellite-None'; 57 | this.GoogleSatelliteNone_Source = [ 58 | { 59 | name: 'Satellite-None', type: 'XYZ_URL', support: true, 60 | source: new ol.source.XYZ({ url: GoogleSatelliteNone_URL }), 61 | url: GoogleSatelliteNone_URL, 62 | coordinateType: 'gcj02', 63 | }, 64 | ]; 65 | // 谷歌地图-路网图-带标注 66 | const GoogleStreet_URL = 'https://mt{1-3}.google.com/maps/vt?lyrs=h%40781&hl=zh-CN&gl=CN&x={x}&y={y}&z={z}'; 67 | this.GoogleStreet_Name = 'Google-Street'; 68 | this.GoogleStreet_Source = [ 69 | { 70 | name: 'Street', type: 'XYZ_URL', support: true, 71 | source: new ol.source.XYZ({ url: GoogleStreet_URL }), 72 | url: GoogleStreet_URL, 73 | coordinateType: 'gcj02', 74 | }, 75 | ]; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /Web/src/app/map/source/mapbox-source.ts: -------------------------------------------------------------------------------- 1 | declare const ol: any; 2 | 3 | export class MapBoxSource { 4 | 5 | MapBoxPDF_Name: string; 6 | MapBoxPDF_Source: Array; 7 | 8 | constructor() { 9 | // Calculation of resolutions that match zoom levels 1, 3, 5, 7, 9, 11, 13, 15. 10 | const resolutions = []; 11 | for (let i = 0; i <= 8; ++i) { 12 | resolutions.push(156543.03392804097 / Math.pow(2, i * 2)); 13 | } 14 | 15 | // Calculation of tile urls for zoom levels 1, 3, 5, 7, 9, 11, 13, 15. 16 | const tileUrlFunction = (tileCoord: number[]) => { 17 | return MapBoxPDF_URL 18 | .replace('{z}', String(tileCoord[0] * 2 - 1)) 19 | .replace('{x}', String(tileCoord[1])) 20 | .replace('{y}', String(tileCoord[2])) 21 | .replace( 22 | '{a-d}', 23 | 'abcd'.substr(((tileCoord[1] << tileCoord[0]) + tileCoord[2]) % 4, 1) 24 | ); 25 | } 26 | 27 | const key = 'pk.eyJ1IjoiaDYzMjU4MjE4MyIsImEiOiJjbDl6dHg4NmMwajI1M29uejc0bWV2ZHdvIn0.Zk2n4LahjuKP3TG8ih6iCg' 28 | // MapBox-PDF矢量瓦片 29 | const MapBoxPDF_URL = 'https://{a-d}.tiles.mapbox.com/v4/mapbox.mapbox-streets-v6/' + 30 | '{z}/{x}/{y}.vector.pbf?access_token=' + key; 31 | this.MapBoxPDF_Name = 'MapBox-PDF'; 32 | this.MapBoxPDF_Source = [ 33 | { 34 | name: 'MapBox', type: 'PDF', support: true, 35 | source: new ol.source.VectorTile({ 36 | attributions: 37 | '© Mapbox ' + 38 | '© ' + 39 | 'OpenStreetMap contributors', 40 | format: new ol.format.MVT(), 41 | tileGrid: new ol.tilegrid.TileGrid({ 42 | extent: ol.proj.get('EPSG:3857').getExtent(), 43 | resolutions: resolutions, 44 | tileSize: 512, 45 | }), 46 | tileUrlFunction: tileUrlFunction, 47 | }), 48 | url: MapBoxPDF_URL, 49 | coordinateType: 'gcj02', 50 | }, 51 | ]; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /Web/src/app/map/source/osm-source.ts: -------------------------------------------------------------------------------- 1 | declare const ol: any; 2 | 3 | export class OsmSource { 4 | 5 | OpenStreetMap_Name: string; 6 | OpenStreetMap_Source: Array; 7 | 8 | constructor() { 9 | // OpenStreetMap 10 | const OpenStreetMap_URL = 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png'; 11 | this.OpenStreetMap_Name = 'OpenStreet'; 12 | this.OpenStreetMap_Source = [ 13 | { 14 | name: 'Normal', type: 'XYZ_URL', support: true, 15 | source: new ol.source.XYZ({ url: OpenStreetMap_URL }), 16 | url: OpenStreetMap_URL, 17 | coordinateType: 'wgs84', 18 | } 19 | ] 20 | } 21 | 22 | } 23 | 24 | -------------------------------------------------------------------------------- /Web/src/app/map/source/tencent-source.ts: -------------------------------------------------------------------------------- 1 | declare const ol: any; 2 | 3 | export class TencentSource { 4 | 5 | TencentNormal_Name: string; 6 | TencentNormal_Source: Array; 7 | 8 | constructor() { 9 | // 腾讯地图-普通图-带标注 10 | const TencentNormal_URL = 'http://rt0.map.gtimg.com/realtimerender?z={z}&x={x}&y={-y}&type=vector&style=0'; 11 | this.TencentNormal_Name = 'Tencent-Normal'; 12 | this.TencentNormal_Source = [ 13 | { 14 | name: 'Normal', type: 'XYZ_URL', support: true, 15 | source: new ol.source.XYZ({ url: TencentNormal_URL }), 16 | url: TencentNormal_URL, 17 | coordinateType: 'gcj02', 18 | }, 19 | ]; 20 | } 21 | 22 | } 23 | 24 | -------------------------------------------------------------------------------- /Web/src/app/map/source/tian-source.ts: -------------------------------------------------------------------------------- 1 | import { CommonUtil } from "src/app/util/common-util"; 2 | 3 | declare const ol: any; 4 | 5 | export class TianSource { 6 | 7 | TiandituNormalNone_Name: string; 8 | TiandituNormalNone_Source: Array; 9 | 10 | TiandituTerrainNone_Name: string; 11 | TiandituTerrainNone_Source: Array; 12 | 13 | TiandituLine_Name: string; 14 | TiandituLine_Source: Array; 15 | 16 | TiandituTip_Name: string; 17 | TiandituTip_Source: Array; 18 | 19 | constructor() { 20 | // 天地图-普通图-无标注 21 | const TiandituNormalNone_URL = "https://t{0-7}.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=&&&&&&&key&&&&&&&"; 22 | this.TiandituNormalNone_Name = 'Tianditu-Normal-None'; 23 | this.TiandituNormalNone_Source = [ 24 | { 25 | name: "Normal-None", type: "XYZ_URL", support: true, 26 | source: new ol.source.XYZ({ url: TiandituNormalNone_URL.replace("&&&&&&&key&&&&&&&", CommonUtil.getConfigCache().key.tian) }), 27 | url: TiandituNormalNone_URL, 28 | coordinateType: "wgs84" 29 | } 30 | ]; 31 | // 天地图-地形图-无标注 32 | const TiandituTerrainNone_URL = "https://t{0-7}.tianditu.gov.cn/ter_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=&&&&&&&key&&&&&&&"; 33 | this.TiandituTerrainNone_Name = 'Tianditu-Terrain-None'; 34 | this.TiandituTerrainNone_Source = [ 35 | { 36 | name: "Terrain-None", type: "XYZ_URL", support: true, 37 | source: new ol.source.XYZ({ url: TiandituTerrainNone_URL.replace("&&&&&&&key&&&&&&&", CommonUtil.getConfigCache().key.tian) }), 38 | url: TiandituTerrainNone_URL, 39 | coordinateType: "wgs84" 40 | } 41 | ]; 42 | // 天地图-边界线 43 | const TiandituLine_URL = "https://t{0-7}.tianditu.gov.cn/ibo_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ibo&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=&&&&&&&key&&&&&&&"; 44 | this.TiandituLine_Name = 'Tianditu-Line'; 45 | this.TiandituLine_Source = [ 46 | { 47 | name: "Normal-Tip", type: "XYZ_URL", support: true, 48 | source: new ol.source.XYZ({ url: TiandituLine_URL.replace("&&&&&&&key&&&&&&&", CommonUtil.getConfigCache().key.tian) }), 49 | url: TiandituLine_URL, 50 | coordinateType: "wgs84" 51 | } 52 | ]; 53 | // 天地图-标注层 54 | const TiandituTip_URL = "https://t{0-7}.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=&&&&&&&key&&&&&&&"; 55 | this.TiandituTip_Name = 'Tianditu-Tip'; 56 | this.TiandituTip_Source = [ 57 | { 58 | name: "Normal-Tip", type: "XYZ_URL", support: true, 59 | source: new ol.source.XYZ({ url: TiandituTip_URL.replace("&&&&&&&key&&&&&&&", CommonUtil.getConfigCache().key.tian) }), 60 | url: TiandituTip_URL, 61 | coordinateType: "wgs84" 62 | } 63 | ]; 64 | } 65 | 66 | } 67 | 68 | -------------------------------------------------------------------------------- /Web/src/app/model/add-layer.type.ts: -------------------------------------------------------------------------------- 1 | export type AddLayerType = { 2 | name: string, 3 | url: string, 4 | type: string, 5 | proxy: boolean, 6 | } 7 | -------------------------------------------------------------------------------- /Web/src/app/rx/inner-mq/client/impl/lo-inner-mq.client.ts: -------------------------------------------------------------------------------- 1 | import { NormalInnerMqClient } from "./normal-inner-mq.client"; 2 | import { Topic } from "../../topic"; 3 | import { Observable, Subject } from "rxjs"; 4 | import { PersistentType } from "../../service/inner-mq.service"; 5 | 6 | /** 7 | * 支持本地回环模式的客户端 8 | * 即自己可以给自己发消息,不需要通过服务端接收 9 | * 类似于 127.0.0.1 10 | * */ 11 | export class LoInnerMqClient extends NormalInnerMqClient { 12 | 13 | // 持久化队列,仅本地回环支持 14 | private persistentQueue = new Map>(); 15 | 16 | constructor( 17 | id: string, 18 | callback: { 19 | onSubscribe: (topic: Topic, subject: Subject) => void 20 | } 21 | ) { 22 | super(id, callback); 23 | } 24 | 25 | /* 订阅 */ 26 | public override sub(topic: Topic, subscribe: (e: T) => void): string { 27 | let res = super.sub(topic, subscribe); 28 | // 完成父类sub方法后发送持久化消息 29 | let subject = this.subjects.get(topic); 30 | if (subject != null) { 31 | this.processPersistentQueue(topic, subject); 32 | } 33 | return res; 34 | } 35 | 36 | /* 发布 */ 37 | public override pub(topic: Topic, msg: any, option?: { persistent: boolean, type: PersistentType }): void { 38 | let published = false; 39 | if (!this.destroyed) { 40 | let subject = this.subjects.get(topic); 41 | if (subject != null && !subject.closed) { 42 | subject.next(msg); 43 | published = true; 44 | } 45 | } 46 | // 消息未发送,进行持久化存储 47 | if (!published && (option && option.persistent)) { 48 | if (this.persistentQueue.get(topic) == null) { 49 | this.persistentQueue.set(topic, []); 50 | } 51 | this.persistentQueue.get(topic)?.push({ type: option.type, data: msg }); 52 | } 53 | } 54 | 55 | /* 处理持久化消息 */ 56 | private processPersistentQueue(topic: Topic, subject: Subject): void { 57 | let queue = this.persistentQueue.get(topic); 58 | if (queue == null) { 59 | return; 60 | } 61 | // 异步发送已持久化的消息 62 | new Observable((observer) => { 63 | Promise.resolve().then(() => { 64 | observer.next(true); 65 | }) 66 | }).subscribe(() => { 67 | if (queue == null) { 68 | return; 69 | } 70 | for (let i = 0; i < queue.length; i++) { 71 | switch (queue[i].type) { 72 | case PersistentType.ON_ONCE_SUB: 73 | subject.next(queue[i].data); 74 | queue.splice(i, 1); // 将使后面的元素依次前移,数组长度减1 75 | i--; // 如果不减,将漏掉一个元素 76 | break; 77 | case PersistentType.ON_EVERY_CLIENT_EVERY_SUB: 78 | subject.next(queue[i].data); 79 | break; 80 | default: 81 | break; 82 | } 83 | } 84 | if (queue.length == 0) { 85 | this.persistentQueue.delete(topic); 86 | } 87 | }); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /Web/src/app/rx/inner-mq/client/impl/normal-inner-mq.client.ts: -------------------------------------------------------------------------------- 1 | import { Subject, Subscription } from "rxjs"; 2 | import { InnerMqClient } from "../inner-mq.client"; 3 | import { Topic } from "../../topic"; 4 | import { Random } from "../../util/random"; 5 | 6 | export class NormalInnerMqClient implements InnerMqClient { 7 | 8 | protected subjects: Map> = new Map>(); // 实例 9 | protected subscriptions: Array<{ id: string, topic: Topic, subscription: Subscription }> = []; // 订阅列表 10 | protected destroyed = false; 11 | 12 | constructor( 13 | protected readonly id: string, 14 | protected callback: { 15 | onSubscribe: (topic: Topic, subject: Subject) => void 16 | } 17 | ) { 18 | } 19 | 20 | public getId(): string { 21 | return this.id; 22 | } 23 | 24 | public getSubject(topic: Topic): Subject | undefined { 25 | return this.subjects.get(topic); 26 | } 27 | 28 | public isDestroyed(): boolean { 29 | return this.destroyed; 30 | } 31 | 32 | /* 订阅 */ 33 | public sub(topic: Topic, subscribe: (e: T) => void): string { 34 | let subject = this.subjects.get(topic); 35 | if (subject == null) { 36 | subject = new Subject(); 37 | this.subjects.set(topic, subject); 38 | } 39 | let id = this.getSubscriptionId(); 40 | let subscription = subject.subscribe(res => subscribe(res)); 41 | this.subscriptions.push({ id: id, topic: topic, subscription: subscription }); 42 | this.callback.onSubscribe(topic, subject); 43 | return id; 44 | } 45 | 46 | /* 发布 */ 47 | public pub(topic: Topic, msg: any): void { 48 | console.error('仅lo-client支持内部发布'); 49 | } 50 | 51 | /* 取消订阅 By Topic */ 52 | public stopSubByTopic(topic: Topic): void { 53 | for (let i = 0; i < this.subscriptions.length; i++) { 54 | if (topic == this.subscriptions[i].topic) { 55 | this.subscriptions[i].subscription.unsubscribe(); 56 | this.subscriptions.splice(i, 1); 57 | i--; 58 | } 59 | } 60 | } 61 | 62 | /* 取消订阅 By Id */ 63 | public stopSubBySubscriptionId(id: string): void { 64 | for (let i = 0; i < this.subscriptions.length; i++) { 65 | if (id == this.subscriptions[i].id) { 66 | this.subscriptions[i].subscription.unsubscribe(); 67 | this.subscriptions.splice(i, 1); 68 | i--; 69 | } 70 | } 71 | } 72 | 73 | /* 销毁 */ 74 | public destroy(): void { 75 | this.destroyed = true; 76 | for (let i = 0; i < this.subscriptions.length; i++) { 77 | this.subscriptions[i].subscription.unsubscribe(); 78 | } 79 | for (let subject of this.subjects.values()) { 80 | subject.unsubscribe(); 81 | } 82 | this.subjects.clear(); 83 | } 84 | 85 | private getSubscriptionId(): string { 86 | let id = Random.generateCharMixed(20); 87 | for (let i = 0; i < this.subscriptions.length; i++) { 88 | if (id == this.subscriptions[i].id) { 89 | this.getSubscriptionId(); 90 | } 91 | } 92 | return id; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /Web/src/app/rx/inner-mq/client/inner-mq.client.ts: -------------------------------------------------------------------------------- 1 | import { Subject } from "rxjs"; 2 | import { Topic } from "../topic"; 3 | import { PersistentType } from "../service/inner-mq.service"; 4 | 5 | export interface InnerMqClient { 6 | 7 | getId(): string; 8 | 9 | getSubject(topic: Topic): Subject | undefined; 10 | 11 | isDestroyed(): boolean; 12 | 13 | sub(topic: Topic, subscribe: (e: T) => void): string; 14 | 15 | pub(topic: Topic, msg: any, option?: { persistent: boolean, type: PersistentType }): void; 16 | 17 | stopSubByTopic(topic: Topic): void; 18 | 19 | stopSubBySubscriptionId(id: string): void; 20 | 21 | destroy(): void; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Web/src/app/rx/inner-mq/topic.ts: -------------------------------------------------------------------------------- 1 | export enum Topic { 2 | 3 | INIT_MAP_CONFIG = 'initMapConfig', 4 | ZOOM_IN = 'ZoomIn', 5 | ZOOM_OUT = 'ZoomOut', 6 | PAN = 'Pan', 7 | FIT_VIEW = 'FitView', 8 | GRID_SWITCH = 'GridSwitch', 9 | SWITCH_RESOURCE = 'SwitchResource', 10 | SWITCH_ADDED_RESOURCE = 'SwitchAddedResource', 11 | REMOVE_ADDED_RESOURCE = 'RemoveAddedResource', 12 | SWITCH_DRAW_TYPE = 'SwitchDrawType', 13 | OPEN_DRAW = 'OpenDraw', 14 | DRAW_POLYGON_AND_POSITING = 'DrawPolygonAndPositing', 15 | REMOVE_SHAPE = 'RemoveShape', 16 | SUBMIT_BLOCK_DOWNLOAD = 'SubmitBlockDownload', 17 | SUBMIT_WORLD_DOWNLOAD = 'SubmitWorldDownload', 18 | 19 | } 20 | -------------------------------------------------------------------------------- /Web/src/app/rx/inner-mq/util/random.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 像Math.seededRandom这种伪随机数生成器叫做线性同余生成器(LCG, Linear Congruential Generator),几乎所有的运行库提供的rand都是采用的LCG,形如: 3 | * I n+1=aI n+c(mod m) 4 | * 生成的伪随机数序列最大周期m,范围在0到m-1之间。要达到这个最大周期,必须满足: 5 | * 1.c与m互质 6 | * 2.a - 1可以被m的所有质因数整除 7 | * 3.如果m是4的倍数,a - 1也必须是4的倍数 8 | * 以上三条被称为Hull-Dobell定理。作为一个伪随机数生成器,周期不够大是不好意思混的,所以这是要求之一。因此才有了:a=9301, c = 49297, m = 233280这组参数,以上三条全部满足。 9 | * */ 10 | export class Random { 11 | 12 | private seed: number; 13 | 14 | // 实例化一个随机数生成器,seed=随机数种子,默认当前时间 15 | constructor(seed?: number) { 16 | this.seed = (seed || Date.now()) % 999999999; 17 | } 18 | 19 | // 返回0~1之间的数 20 | public next() { 21 | this.seed = (this.seed * 9301 + 49297) % 233280; 22 | return this.seed / 233280.0; 23 | } 24 | 25 | // 返回0~max之间的数 26 | public nextInt(max: number) { 27 | return Math.floor(this.next() * max); 28 | } 29 | 30 | // 静态方法:生成n位数字字母混合字符串 31 | public static generateCharMixed(n: number) { 32 | let chars = [ 33 | '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 34 | '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '+', '*', 35 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 36 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 37 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 38 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 39 | ]; 40 | let res = ''; 41 | for (let i = 0; i < n; i++) { 42 | let id = Math.floor(Math.random() * chars.length); 43 | res += chars[id]; 44 | } 45 | return res; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /Web/src/app/service/info.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClientService } from '../http/http-client.service'; 3 | import { HttpMethod } from '../http/http-method'; 4 | import { RESTfulResult } from '../http/restful-result.type'; 5 | 6 | @Injectable() 7 | export class InfoService { 8 | 9 | constructor(private http: HttpClientService) { 10 | } 11 | 12 | /** 获取WS路径 */ 13 | public getWsPath(): Promise { 14 | return this.http.request({ 15 | method: HttpMethod.GET, 16 | url: '/info/getWsPath', 17 | data: null, 18 | }) 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Web/src/app/service/submit.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClientService } from '../http/http-client.service'; 3 | import { HttpMethod } from '../http/http-method'; 4 | import { RESTfulResult } from '../http/restful-result.type'; 5 | 6 | @Injectable() 7 | export class SubmitService { 8 | 9 | constructor(private http: HttpClientService) { 10 | } 11 | 12 | /** 提交区域下载 */ 13 | public blockDownload(data: any): Promise { 14 | return this.http.request({ 15 | method: HttpMethod.POST, 16 | url: '/submit/blockDownload', 17 | data: data 18 | }) 19 | } 20 | 21 | /** 世界下载 */ 22 | public worldDownload(data: any): Promise { 23 | return this.http.request({ 24 | method: HttpMethod.POST, 25 | url: '/submit/worldDownload', 26 | data: data 27 | }) 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Web/src/app/view/page/index.page-module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { provideRouter, RouterOutlet } from "@angular/router"; 4 | import { IndexPage } from './index.page'; 5 | 6 | @NgModule({ 7 | imports: [ 8 | CommonModule, 9 | RouterOutlet, 10 | ], 11 | declarations: [ 12 | IndexPage, 13 | ], 14 | providers: [ 15 | provideRouter([ 16 | { path: '', redirectTo: 'map-control', pathMatch: 'full' }, 17 | { 18 | path: '', component: IndexPage, children: [ 19 | { // 地图操作页面 20 | path: 'map-control', 21 | loadChildren: () => import('./map-control/map-control.page-module').then(mod => mod.MapControlPageModule) 22 | }, 23 | { // 瓦片预览页面 24 | path: 'tile-view', 25 | loadChildren: () => import('./tile-view/tile-view.page-module').then(mod => mod.TileViewPageModule) 26 | }, 27 | ] 28 | }, 29 | ]), 30 | ], 31 | }) 32 | export class IndexPageModule { 33 | } 34 | -------------------------------------------------------------------------------- /Web/src/app/view/page/index.page.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /Web/src/app/view/page/index.page.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | width: 100%; 3 | height: 100vh; 4 | } -------------------------------------------------------------------------------- /Web/src/app/view/page/index.page.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-index', 5 | templateUrl: './index.page.html', 6 | styleUrls: ['./index.page.scss'], 7 | }) 8 | export class IndexPage { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /Web/src/app/view/page/map-control/dialog/key-input-dialog.component.html: -------------------------------------------------------------------------------- 1 |

更换Key

2 |
3 | 4 | 请输入你的Key 5 | 6 | 7 | {{ getErrorMessage() }} 8 | 9 | 10 |
11 |
12 | 13 | 14 |
15 | -------------------------------------------------------------------------------- /Web/src/app/view/page/map-control/dialog/key-input-dialog.component.scss: -------------------------------------------------------------------------------- 1 | .input { 2 | width: 100%; 3 | } 4 | -------------------------------------------------------------------------------- /Web/src/app/view/page/map-control/dialog/key-input-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Inject, OnInit } from "@angular/core"; 2 | import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog"; 3 | import { FormControl, Validators } from "@angular/forms"; 4 | 5 | @Component({ 6 | selector: 'com-key-input-dialog', 7 | styleUrls: ['key-input-dialog.component.scss'], 8 | templateUrl: 'key-input-dialog.component.html', 9 | }) 10 | export class KeyInputDialogComponent implements OnInit { 11 | 12 | key = new FormControl('', [Validators.required]); 13 | 14 | constructor( 15 | @Inject(MAT_DIALOG_DATA) 16 | private data: { defaultKey: string, callback: (key: string) => void }, 17 | private dialogRef: MatDialogRef, 18 | ) { 19 | } 20 | 21 | ngOnInit(): void { 22 | this.key.setValue(this.data.defaultKey); 23 | } 24 | 25 | getErrorMessage(): String { 26 | return this.key.hasError('required') ? 'Key不能为空' : ''; 27 | } 28 | 29 | submit(): void { 30 | if (this.key.hasError('required') || this.key.value == null) { 31 | return; 32 | } 33 | this.data.callback(this.key.value); 34 | this.dialogRef.close(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Web/src/app/view/page/map-control/map-control.page-module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { provideRouter } from "@angular/router"; 4 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 5 | import { MatButtonModule } from '@angular/material/button'; 6 | import { MatDialogModule } from "@angular/material/dialog"; 7 | import { MatFormFieldModule } from "@angular/material/form-field"; 8 | import { MatInputModule } from "@angular/material/input"; 9 | import { MapControlPage } from './map-control.page'; 10 | import { KeyInputDialogComponent } from "./dialog/key-input-dialog.component"; 11 | 12 | @NgModule({ 13 | imports: [ 14 | CommonModule, 15 | FormsModule, 16 | ReactiveFormsModule, 17 | MatButtonModule, 18 | MatDialogModule, 19 | MatFormFieldModule, 20 | MatInputModule, 21 | ], 22 | declarations: [ 23 | MapControlPage, 24 | KeyInputDialogComponent, 25 | ], 26 | providers: [ 27 | provideRouter([ 28 | { path: '', component: MapControlPage }, 29 | ]), 30 | ], 31 | }) 32 | export class MapControlPageModule { 33 | } 34 | -------------------------------------------------------------------------------- /Web/src/app/view/page/map-control/map-control.page.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
Zoom: {{ zoom }}
5 |
6 | 7 |
8 | 9 |
10 | 11 |
12 | 13 |
14 | 15 |
16 | 19 |
20 |
21 |
22 | 23 |
24 | 27 |
28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Web/src/app/view/page/map-control/map-control.page.scss: -------------------------------------------------------------------------------- 1 | .map { 2 | width: 100%; 3 | height: 100%; 4 | } 5 | 6 | .zoom { 7 | position: absolute; 8 | top: 8px; 9 | left: 8px; 10 | padding: 3px 5px 3px 5px; 11 | border-radius: 4px; 12 | background: rgba(0, 60, 136, 0.4); 13 | color: #eee; 14 | font-size: 14px; 15 | text-align: center; 16 | user-select: none; 17 | } 18 | 19 | .right-top { 20 | position: absolute; 21 | top: 8px; 22 | right: 8px; 23 | 24 | .block { 25 | float: left; 26 | margin-left: 8px; 27 | } 28 | } 29 | 30 | .right-bottom { 31 | position: absolute; 32 | bottom: 8px; 33 | right: 8px; 34 | 35 | .block { 36 | float: left; 37 | margin-left: 8px; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Web/src/app/view/page/tile-view/tile-view.page-module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { provideRouter } from "@angular/router"; 4 | import { MatButtonModule } from "@angular/material/button"; 5 | import { TileViewPage } from "./tile-view.page"; 6 | 7 | @NgModule({ 8 | imports: [ 9 | CommonModule, 10 | MatButtonModule, 11 | ], 12 | declarations: [ 13 | TileViewPage, 14 | ], 15 | providers: [ 16 | provideRouter([ 17 | { path: '', component: TileViewPage }, 18 | ]), 19 | ], 20 | }) 21 | export class TileViewPageModule { 22 | } 23 | -------------------------------------------------------------------------------- /Web/src/app/view/page/tile-view/tile-view.page.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 |
6 | 9 |
10 | 11 |
12 | 15 |
16 |
17 | -------------------------------------------------------------------------------- /Web/src/app/view/page/tile-view/tile-view.page.scss: -------------------------------------------------------------------------------- 1 | .map { 2 | width: 100%; 3 | height: 100%; 4 | } 5 | 6 | .right-top { 7 | position: absolute; 8 | top: 8px; 9 | right: 8px; 10 | 11 | .block { 12 | float: left; 13 | margin-left: 8px; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Web/src/app/view/page/tile-view/tile-view.page.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from "@angular/core"; 2 | import { MapBaseSimple } from "src/app/map/map-base-simple"; 3 | 4 | @Component({ 5 | selector: 'app-tile-view', 6 | templateUrl: './tile-view.page.html', 7 | styleUrls: ['./tile-view.page.scss'], 8 | }) 9 | export class TileViewPage implements OnInit, OnDestroy { 10 | 11 | @ViewChild('map', { static: true }) mapEleRef!: ElementRef; 12 | 13 | zoom: number = 0; 14 | gridOpen: boolean = true; 15 | 16 | private mapBase!: MapBaseSimple; 17 | 18 | ngOnInit(): void { 19 | this.mapBase = new MapBaseSimple(this.mapEleRef.nativeElement, { 20 | tileUrl: 'http://localhost:26737/tile/local?z={z}&x={x}&y={y}', 21 | }, { 22 | onFinish: () => { 23 | this.mapBase.getOlMap().on('moveend', (e: any) => { 24 | let z = e.map.getView().getZoom(); 25 | if (z != null) { 26 | this.zoom = Math.round(z); 27 | } 28 | }) 29 | }, 30 | }); 31 | } 32 | 33 | ngOnDestroy(): void { 34 | this.mapBase.destroyMap(); 35 | } 36 | 37 | gridOpenClose(): void { 38 | this.gridOpen = !this.gridOpen; 39 | this.gridOpen ? this.mapBase.showGrid() : this.mapBase.closeGrid(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Web/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /Web/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /Web/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kurimuson/java_map_download/743dfa5b699efc44efa85004f73bd6fe7fca13ef/Web/src/favicon.ico -------------------------------------------------------------------------------- /Web/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Web 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Web/src/main.ts: -------------------------------------------------------------------------------- 1 | import {enableProdMode} from '@angular/core'; 2 | import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; 3 | 4 | import {AppModule} from './app/app.module'; 5 | import {environment} from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /Web/src/styles.scss: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | -------------------------------------------------------------------------------- /Web/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /Web/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "types": [ 8 | "Node" 9 | ], 10 | "forceConsistentCasingInFileNames": true, 11 | "strict": true, 12 | "noImplicitOverride": true, 13 | "noPropertyAccessFromIndexSignature": true, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "sourceMap": true, 17 | "declaration": false, 18 | "downlevelIteration": true, 19 | "experimentalDecorators": true, 20 | "moduleResolution": "node", 21 | "importHelpers": true, 22 | "target": "es2020", 23 | "module": "esNext", 24 | "lib": [ 25 | "es2020", 26 | "dom" 27 | ] 28 | }, 29 | "angularCompilerOptions": { 30 | "enableI18nLegacyMessageIdFormat": false, 31 | "strictInjectionParameters": true, 32 | "strictInputAccessModifiers": true, 33 | "strictTemplates": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Web/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /若README.md无法正常显示,将项目fork到自己下面即可正常查看: -------------------------------------------------------------------------------- 1 | 若README.md无法正常显示,将项目fork到自己下面即可正常查看 --------------------------------------------------------------------------------