feat(version): add fixed-jar release version management
| | |
| | | > **æ¯å¤©ç»ææ¶**ï¼æå½å¤©è¿å±ã踩è¿çåãæ°éæ±ãæªå®æäºé¡¹æ´æ°å°æ¬æä»¶ï¼ç¶åå¯ä»¥æ¾å¿å¼æ°å¯¹è¯ã |
| | | > **åä½çº¦å®ï¼2026-08-31ï¼**ï¼è¯´ãæäº¤ã= æ¬å° commit + æ¨éå°è¿ç«¯ gitï¼origin mainï¼Gitblitï¼ï¼ä¸ååªåæ¬å° commitã |
| | | |
| | | ## ææ°ï¼2026-10-04ï¼ |
| | | ## ææ°ï¼2026-10-05ï¼ |
| | | |
| | | ### 10-05ï¼çæ¬ç®¡çéç¨æ¹æ¡ Aï¼åºå® jar åï¼å·²å®æå¹¶éè¿æµè¯ï¼ |
| | | |
| | | - **ç¨æ·å³ç**ï¼éç¨æ¹æ¡ Aã`traffic-audit-server/pom.xml` 为å¯ä¸çæ¬æºï¼å½å对å¤çæ¬ `1.0.0`ã |
| | | - **æå»ºæ¹é **ï¼`<finalName>traffic-audit-server</finalName>`ï¼äº§ç©åºå®ä¸º `target/traffic-audit-server.jar`ï¼Maven èµæºè¿æ»¤çæ `app-version.properties`ï¼Spring Boot ç¶ POM ä½¿ç¨ `@project.version@` åé符ï¼ï¼`maven-jar-plugin` åå
¥ `Implementation-Version`ã |
| | | - **页颿¾ç¤º**ï¼æ°å¢å
ç»å½ `GET /api/version`ï¼ç»å½é¡µå页头æ¾ç¤º `V1.0.0`ãåæ¶ä¿®å¤å¯æ§è¡ jar ä¸ `buildTime` 为 `null` çåµå¥ URI è§£æé®é¢ã |
| | | - **åå¸é¾è·¯**ï¼æå¡ XMLãå¯å¨èæ¬ãæå
èæ¬å
¨é¨æ¹ç¨åºå® jar åï¼`pack-deploy.ps1` 伿 ¡éª pom / `app-version.properties` / `MANIFEST.MF` ä¸è
çæ¬ä¸è´ï¼åå¸å
å为 `traffic-audit-deploy-YYYYMMDD-v1.0.0(.zip)`ï¼å¹¶è¾åºå¸¦ `{version}` çé¨ç½² READMEã |
| | | - **æ§æå¡å¨é¦æ¬¡å级ï¼ä»
䏿¬¡ï¼**ï¼åæ¢æå¡åï¼æ `trafficAudit.xml` ç `<arguments>` æ¹ä¸º `-Dfile.encoding=UTF-8 -jar "%BASE%\traffic-audit-server.jar"`ï¼æ¿æ¢ jar åå¯å¨ã以ååçåªæ¿æ¢ jar å¹¶éå¯ï¼ä¸åæ¹ XMLã |
| | | - **éªè¯**ï¼`mvn -o test`ã`mvn -o clean package -DskipTests`ãåºå®å jar å®é
å¯å¨å¹¶è®¿é® `/api/version`ãå端 `npm run build`ãæ¬å°æµè§å¨ç»å½é¡µæ¾ç¤º `V1.0.0`ã`pack-deploy.ps1 -SkipFrontend -NoFrontendDist -SkipServiceWrapper` ç»è£
/å»å¯/çæ¬èªæ£å
¨é¨éè¿ï¼è´åéªè¯ç¡®è®¤çæ¬ä¸å¹é
å `SNAPSHOT` é½ä¼å¨æå
å䏿¢ãæµè¯æ¥åï¼æ¬å° `docs/åè½æµè¯æ¥å/åè½æµè¯æ¥å_çæ¬ç®¡çæ¹æ¡A_2026-10-05.md`ï¼ç®å½ä¸å
¥åºï¼ã |
| | | - **ç¶æ**ï¼ä»£ç ä¸ææ¡£å·²æ¹å®ï¼åå¤æäº¤å¹¶æ `v1.0.0` æ ç¾ï¼å°æªéæ°çææ£å¼åå¸å
ã |
| | | |
| | | ### 10-04 æ·±å¤ï¼æçº¿æ°å¼æ ç¾åå°è´´è¿æ¬ç¹ï¼v35ï¼å¾
ç¨æ·éªæ¶ï¼ |
| | | |
| | | - **ç¨æ·åé¦**ï¼v31ãé¿å¼æçº¿ãçæ¬ä¸å¦ä¸ä¸ç v27 ââ è½ç¶æ ç¾ä¸å线äºï¼ä½å¾å¤æ ç¾ç¦»èªå·±çæ°æ®ç¹å¤ªè¿ï¼ä¸ç¼çä¸åºæ çæ¯åªä¸ªç¹ãè¦æ±åå°è´´è¿æ¬ç¹çææã |
| | |
| | | TrafficAudit 交éè´§è¿ç»è®¡å®¡æ ¸ç³»ç» ââ é¨ç½²å
ï¼{stamp}ï¼ |
| | | TrafficAudit 交éè´§è¿ç»è®¡å®¡æ ¸ç³»ç» ââ é¨ç½²å
ï¼{stamp}ï¼çæ¬ v{version}ï¼ |
| | | ======================================================== |
| | | |
| | | ãæå¡å¨ä¸åªè¦åè¿ 3 æ¥ãï¼å
¶å®æä»¶é½ä¸ç¨å¨ï¼ |
| | |
| | | |
| | | ãç®å½ç»æã |
| | | backend/ |
| | | traffic-audit-server-1.0.0-SNAPSHOT.jar å端ç¨åºï¼å«å
¨é¨ä¾èµï¼**å·²å
åµå端**ï¼ |
| | | traffic-audit-server.jar å端ç¨åºï¼å«å
¨é¨ä¾èµï¼**å·²å
åµå端**ï¼åºå®æä»¶åï¼ |
| | | docs/ æ¥è¡¨æ¨¡æ¿ä¸è¿è¡æ°æ®ç®å½ï¼å¿
éï¼å¿å ï¼ |
| | | application.yml å¤é¨é
ç½®ï¼æ¹è¿éå³å¯ï¼æ ééæ°æå
ï¼ |
| | | start-backend.cmd / start-backend.sh åå°å¯å¨èæ¬ï¼äººå·¥è°è¯ç¨ï¼å
³äºçªå£å°±åï¼ |
| | |
| | | - èæ¬è¦æ±ï¼install-service.ps1 å¨ Windows PowerShell 2.0+ ä¸å¯ç¨ï¼Win7 èªå¸¦ 2.0ï¼å·²åå
¼å®¹ï¼ï¼ |
| | | 3.2 ç计åä»»å¡èæ¬ç¨å°äº New-ScheduledTask* å½ä»¤ï¼éè¦ Win8 / Server 2012 å以ä¸ã |
| | | |
| | | ã仿¬çèµ·ï¼å端 jar 使ç¨åºå®æä»¶åã |
| | | backend\traffic-audit-server.jar |
| | | - æ°æå¡å¨ï¼æä¸é¢çæ®éé¨ç½²æ¥éª¤æ§è¡å³å¯ã |
| | | - å·²å®è£
æ§çæå¡çæå¡å¨ï¼é¦æ¬¡åçº§å°æ¬çï¼ï¼ |
| | | 1) 忢æå¡ï¼Stop-Service TrafficAuditBackend |
| | | 2) å¤ä»½å¹¶ç¼è¾ backend\trafficAudit.xmlï¼æ <arguments> éçæ§ jar åæ¹æ traffic-audit-server.jar |
| | | 3) æ¿æ¢ backend\traffic-audit-server.jarï¼åæ§è¡ Start-Service TrafficAuditBackend |
| | | - ä»¥åæ¯æ¬¡å级ï¼åªæ¿æ¢ backend\traffic-audit-server.jarï¼åé坿å¡ï¼ä¸åéè¦ä¿®æ¹ trafficAudit.xmlã |
| | | - 页é¢ç»å½é¡µåå³ä¸è§æ¾ç¤ºççæ¬å·ä¸æ¬åå¸å
åç§°ä¸ççæ¬å·ä¸è´ã |
| | | |
| | | ãé¨ç½²æ¥éª¤ã |
| | | 1. åå§åæ°æ®åºï¼4 ä¸ªèæ¬é½è¦æ§è¡ï¼é¡ºåºå¦ä¸ï¼ |
| | | mysql --default-character-set=utf8mb4 -u root -p < db/init.sql |
| | |
| | | |
| | | Assert-Admin |
| | | if (-not (Test-Path $launcher)) { throw "Missing launcher: $launcher" } |
| | | if (-not (Test-Path (Join-Path $root 'traffic-audit-server-1.0.0-SNAPSHOT.jar'))) { |
| | | if (-not (Test-Path (Join-Path $root 'traffic-audit-server.jar'))) { |
| | | Write-Host "WARN: jar not found in $root - the task will be registered, but startup will fail until the jar is there." |
| | | } |
| | | |
| | |
| | | <# |
| | | <# |
| | | Install / update / remove the TrafficAudit backend as a Windows service. |
| | | |
| | | The service is a WinSW (Windows Service Wrapper) host: trafficAudit.exe reads |
| | | trafficAudit.xml and runs "java -jar traffic-audit-server-<version>.jar". |
| | | trafficAudit.xml and runs "java -jar traffic-audit-server.jar". |
| | | Because it is a real Windows service it starts at boot with no user logged on, |
| | | is listed in services.msc / Get-Service, and is restarted by the Service |
| | | Control Manager when the java process dies. |
| | |
| | | setlocal |
| | | cd /d "%~dp0" |
| | | |
| | | set "APP_JAR=traffic-audit-server-1.0.0-SNAPSHOT.jar" |
| | | set "APP_JAR=traffic-audit-server.jar" |
| | | set "LOG=%~dp0app.log" |
| | | |
| | | netstat -ano | findstr /C:":8090" | findstr /I "LISTENING" >nul 2>nul |
| | |
| | | echo å端已å
åµï¼ç´æ¥è®¿é® 8090 å³å¯ï¼ä¸éè¦ nginxï¼ |
| | | echo æ¥å¿æ¾ç¤ºå¨æ¬çªå£ï¼å
³éçªå£å³åæ¢æå¡ |
| | | echo ============================================ |
| | | java -jar traffic-audit-server-1.0.0-SNAPSHOT.jar |
| | | java -jar traffic-audit-server.jar |
| | | pause |
| | |
| | | echo "[WARN] application.yml é spring.datasource.password è¿æ¯å 使åï¼è¯·å
æ¹æçå® MySQL å¯ç " |
| | | fi |
| | | echo "TrafficAudit å¯å¨ä¸ï¼http://localhost:8090 ï¼Ctrl+C 忢ï¼" |
| | | java -jar traffic-audit-server-1.0.0-SNAPSHOT.jar 2>&1 | tee app.log |
| | | java -jar traffic-audit-server.jar 2>&1 | tee app.log |
| | |
| | | <description>TrafficAudit freight statistics audit backend (Spring Boot, HTTP port 8090).</description> |
| | | |
| | | <executable>java.exe</executable> |
| | | <arguments>-Dfile.encoding=UTF-8 -jar "%BASE%\traffic-audit-server-1.0.0-SNAPSHOT.jar"</arguments> |
| | | <arguments>-Dfile.encoding=UTF-8 -jar "%BASE%\traffic-audit-server.jar"</arguments> |
| | | <workingdirectory>%BASE%</workingdirectory> |
| | | |
| | | <!-- Start at boot, but delayed so a local MySQL service is ready first. --> |
| | |
| | | # 交éç»è®¡æ¥è¡¨å®¡æ ¸ç³»ç» â æå
ä¸é¨ç½²è¯´æ |
| | | |
| | | > éç¨ï¼main åæ¯ï¼ææ°æ´æ° 2026-09-13ï¼ãå端 Spring Boot 2.7ï¼Java 8ï¼ï¼å端 Vue 2 + Element UIã |
| | | > éç¨ï¼main åæ¯ï¼ææ°æ´æ° 2026-10-05ï¼ãå端 Spring Boot 2.7ï¼Java 8ï¼ï¼å端 Vue 2 + Element UIã |
| | | > æ¬ææ¡£é¢åå¼åä¸é¨ç½²åäºï¼å½ä»¤åå¨ Windows ä¸éªè¯ã |
| | | |
| | | ## ä¸ã项ç®ç»æ |
| | |
| | | |
| | | 1. `traffic-audit-web` ä¸ `npm run build` â `dist`ï¼ |
| | | 2. æ `dist` å¤å¶è¿ `traffic-audit-server/src/main/resources/static`ï¼ä½¿ **jar èªå¸¦å端**ï¼å `mvn clean package -DskipTests`ï¼è·å®èªå¨æ¸
空 staticï¼ä¿æä»åºå¹²åï¼ï¼ |
| | | 3. ç»è£
`deploy/traffic-audit-deploy-YYYYMMDD/`ï¼ |
| | | 4. å缩为 `traffic-audit-deploy-YYYYMMDD.zip`ï¼çº¦ 70 MBï¼ã |
| | | 3. ç»è£
`deploy/traffic-audit-deploy-YYYYMMDD-v1.0.0/`ï¼ |
| | | 4. å缩为 `traffic-audit-deploy-YYYYMMDD-v1.0.0.zip`ï¼çº¦ 70 MBï¼ã |
| | | |
| | | æå·¥çä»·å½ä»¤ï¼ä¸æ³ç¨èæ¬æ¶ï¼ï¼ |
| | | |
| | |
| | | |
| | | > 注æï¼æå·¥æ¹å¼è·å®è®°å¾å æ `traffic-audit-server/src/main/resources/static` ä¸çå
容ï¼å¦å伿±¡ææºç ç®å½ã |
| | | |
| | | ### çæ¬ç®¡çä¸åå¸ï¼2026-10-05 èµ·ï¼ |
| | | |
| | | éç¨æ¹æ¡ Aï¼å端 jar 使ç¨åºå®æä»¶åï¼çæ¬å·ç± `pom.xml` å䏿¥æºçæï¼åå¸å
åå git tag å¸¦çæ¬ã |
| | | |
| | | - åä¸çæ¬æºï¼`traffic-audit-server/pom.xml` ç `<version>`ï¼ä¾å¦ `1.0.0` |
| | | - æå»ºäº§ç©åºå®ä¸º `traffic-audit-server/target/traffic-audit-server.jar` |
| | | - æå»ºæ¶èªå¨æçæ¬åè¿ï¼ |
| | | - `BOOT-INF/classes/app-version.properties` |
| | | - `META-INF/MANIFEST.MF` ç `Implementation-Version` |
| | | - åå¸å
å½åï¼`traffic-audit-deploy-YYYYMMDD-v1.0.0(.zip)` |
| | | - git tag å½åï¼`v1.0.0` |
| | | - 页é¢çæ¬ï¼å端 `GET /api/version`ï¼ç»å½é¡µå页头æ¾ç¤º `V1.0.0` |
| | | - `pack-deploy.ps1` 伿 ¡éª `pom.xml`ãjar å
`app-version.properties`ãjar æ¸
åä¸è
çæ¬ä¸è´ï¼ä¸ä¸è´ç´æ¥ä¸æ¢æå
|
| | | |
| | | åæ°çæ¬æµç¨ï¼ |
| | | |
| | | 1. å
æ¹ `traffic-audit-server/pom.xml` ç `<version>`ï¼ä¾å¦ `1.0.1` |
| | | 2. è¿è¡ `pack-deploy.ps1` æå
|
| | | 3. æäº¤ä»£ç å¹¶æ git tagï¼`git tag -a v1.0.1 -m "v1.0.1"` |
| | | 4. æå¡å¨åæ¢æå¡ï¼æ¿æ¢ `traffic-audit-server.jar`ï¼åå¯å¨æå¡ |
| | | |
| | | æ§æå¡å¨é¦æ¬¡å级ï¼åªéå䏿¬¡ï¼ï¼å·²æ `trafficAudit.xml` é常ä»åæ»æ§ jar å `traffic-audit-server-1.0.0-SNAPSHOT.jar`ï¼æ `<arguments>` æ¹æåºå®æä»¶åï¼ |
| | | |
| | | ```xml |
| | | <arguments>-Dfile.encoding=UTF-8 -jar "%BASE%\traffic-audit-server.jar"</arguments> |
| | | ``` |
| | | |
| | | ä»¥åæ¯æ¬¡åå¸åªæ¿æ¢ jar å¹¶é坿å¡ï¼ä¸åä¿®æ¹ `trafficAudit.xml`ã |
| | | |
| | | ## åãé¨ç½²å
å
容 |
| | | |
| | | ``` |
| | | traffic-audit-deploy-YYYYMMDD/ |
| | | traffic-audit-deploy-YYYYMMDD-v1.0.0/ |
| | | ââ backend/ |
| | | â ââ traffic-audit-server-1.0.0-SNAPSHOT.jar å端 + å
åµå端ï¼çº¦ 55 MBï¼ |
| | | â ââ traffic-audit-server.jar å端 + å
åµå端ï¼çº¦ 55 MBï¼åºå®æä»¶åï¼ |
| | | â ââ docs/ 模æ¿ä¸è¿è¡æ°æ®ï¼å¿
éï¼å¿å ï¼ |
| | | â ââ application.yml å¤é¨é
ç½®ï¼æ¹è¿éå³å¯ï¼æ ééæå
ï¼ |
| | | â ââ start-backend.cmd / start-backend.sh å¯å¨èæ¬ï¼äººå·¥åå»/å½ä»¤è¡ï¼ |
| | |
| | | |
| | | ```powershell |
| | | # Windowsï¼åå» start-backend.cmdï¼æ |
| | | cd backend ; java -jar traffic-audit-server-1.0.0-SNAPSHOT.jar |
| | | cd backend ; java -jar traffic-audit-server.jar |
| | | ``` |
| | | |
| | | ```bash |
| | |
| | | |
| | | ## åä¸ãåæ´è®°å½ |
| | | |
| | | - **2026-10-05**ï¼çæ¬ç®¡çéç¨æ¹æ¡ Aã`pom.xml` 为å¯ä¸çæ¬æºï¼jar åºå®å为 `traffic-audit-server.jar`ï¼æå»ºèªå¨æ³¨å
¥ `app-version.properties` ä¸ `MANIFEST.MF`ï¼åå¸å
åå¸¦çæ¬ï¼æ°å¢ `/api/version` 页颿¾ç¤ºï¼é¦æ¬¡åçº§æ§æå¡å¨é䏿¬¡æ§ä¿®æ¹ `trafficAudit.xml`ï¼ä»¥ååªæ¿æ¢ jar å¹¶éå¯ã |
| | | - **2026-10-03**ï¼`pack-deploy.ps1` è¡¥é½å¤ç½® `application.yml`/`docs`/`db`/å¯å¨èæ¬å¹¶åæ¥ `backend\web`ï¼ä¿® `Access denied ... (using password: NO)`ï¼ï¼æ¨¡æ¿ç«¯å£ 8080â8090ï¼æ°å¢ Windows æå¡æ¹å¼å¼æºèªå¯ï¼WinSW 2.12.0 `trafficAudit.exe` + `trafficAudit.xml` + `install-service.ps1`ï¼èªå¨/å»¶è¿å¯å¨ã失败éå¯ãæ¥å¿æ»å¨ï¼ï¼è®¡å任塿¹å¼é为å¤éï¼è¡¥æä½ç³»ç»å
¼å®¹æ§è¯´æã |
| | | - **2026-09-13**ï¼æ°å¢ä¸é®æå
èæ¬ `package-deploy.py`ï¼jar æ¹ä¸ºå
åµå端ï¼é¨ç½²æºä¸åéè¦ nginxï¼ï¼å é¤ Redis ç¸å
³è¯´æï¼ä»£ç æªä½¿ç¨ï¼ï¼è¡¥ `sql_wyc.sql` ä¸ `summary.template-dir`ï¼è¡¥ `jwt.secret` åå¼è§åï¼è¡¥é¨ç½²åéªè¯æ¸
åã |
| | | - 2026-08-27ï¼é¦çï¼zip é¨ç½²å
+ nginx æ¹æ¡ï¼ã |
| | |
| | | # 1) ç¡®è®¤è¿ jar çé
置没æçå®å¯é¥ï¼åºåªçå° ${...}ï¼ |
| | | Select-String -Path traffic-audit-server\src\main\resources\application.yml -Pattern "password:|api-key:|secret:" |
| | | # 2) æå®å
ååéªè¯ä¸æ¬¡ jar å
é¨ |
| | | python -c "import zipfile;print(zipfile.ZipFile('traffic-audit-server/target/traffic-audit-server-1.0.0-SNAPSHOT.jar').read('BOOT-INF/classes/application.yml').decode('utf-8'))" | Select-String "password:|api-key:" |
| | | python -c "import zipfile;print(zipfile.ZipFile('traffic-audit-server/target/traffic-audit-server.jar').read('BOOT-INF/classes/application.yml').decode('utf-8'))" | Select-String "password:|api-key:" |
| | | ``` |
| | | |
| | | |
| | |
| | | 1. ç¨ `deploy-templates/jar-application.yml`ï¼å
¨å ä½ç¬¦ï¼ä¸´æ¶æ¿æ¢æºç `application.yml`ï¼å `mvn clean package -DskipTests`ï¼æå»ºåèªå¨è¿åå¼åæºçå®é
ç½®ï¼ |
| | | 2. **è§£å jar èªæ£**ï¼æ£æ¥ `BOOT-INF/classes/application.yml` æ¯å¦å
¨ä¸ºå ä½ç¬¦ââ䏿¦åç° `sk-` æææå£ä»¤**ç´æ¥ä¸æ¢æå
**ï¼ |
| | | 3. `npm run build` é建å端 `dist`ï¼ |
| | | 4. æ `deploy-templates/` ç»è£
宿´é¨ç½²å
ï¼backend / frontend / db / README-é¨ç½²è¯´æ.txtï¼ââ`backend/` å« jarã`application.yml`ãå¯å¨èæ¬ã`docs/`ã`web/`ï¼ç± dist èªå¨åæ¥ï¼ä¾ 8090 åç«¯å£æ¨¡å¼ï¼ï¼ä»¥å Windows æå¡ä¸ä»¶å¥ `trafficAudit.exe` + `trafficAudit.xml` + `install-service.ps1`ï¼è¾åºå° `<OutRoot>\traffic-audit-deploy-<yyyyMMdd>`ï¼ |
| | | 4. æ `deploy-templates/` ç»è£
宿´é¨ç½²å
ï¼backend / frontend / db / README-é¨ç½²è¯´æ.txtï¼ââ`backend/` å« jarã`application.yml`ãå¯å¨èæ¬ã`docs/`ã`web/`ï¼ç± dist èªå¨åæ¥ï¼ä¾ 8090 åç«¯å£æ¨¡å¼ï¼ï¼ä»¥å Windows æå¡ä¸ä»¶å¥ `trafficAudit.exe` + `trafficAudit.xml` + `install-service.ps1`ï¼è¾åºå° `<OutRoot>\traffic-audit-deploy-<yyyyMMdd>-v<version>`ï¼ |
| | | WinSW ä¼å
ç¨ `deploy-templates\tools\winsw.exe` ç¼åï¼æ ¡éª SHA-256ï¼ï¼ç¼å缺失æåå¸ä¸ç¬¦æ¶èªå¨ä» GitHub 宿¹åå¸é¡µä¸è½½ v2.12.0 x64ï¼è¯¥äº§ç©æªå Authenticode ç¾åï¼å æ¤ä»¥åºå® SHA-256 ä½å®æ´æ§æ ¡éªï¼ï¼ |
| | | 5. 对ç»è£
åçæ´å
åæ«ä¸éææå¯é¥ã |
| | | |
| | |
| | | ### é¨ç½²æºä¸å /æ¢ DeepSeek key |
| | | |
| | | 1. æå
ä¸ä¼ åï¼ç¼è¾ **jar å级**ç `backend/application.yml`ï¼`deepseek.api-key: "ä½ çæ°key"`ï¼ç空åé¡µé¢ AI åæä¸å¯ç¨ï¼å
¶ä½åè½æ£å¸¸ï¼ï¼ |
| | | 2. éå¯å端ï¼`start-backend.cmd`ï¼æ `java -jar traffic-audit-server-1.0.0-SNAPSHOT.jar`ï¼ï¼ |
| | | 2. éå¯å端ï¼`start-backend.cmd`ï¼æ `java -jar traffic-audit-server.jar`ï¼ï¼ |
| | | 3. 页é¢éç¹ä¸æ¬¡ AI åæç¡®è®¤å¯ç¨ï¼ |
| | | 4. **ä¸è¦**廿¹ jar å
é¨çé
ç½®ï¼æ¹äºä¸æ¬¡åå
就丢ï¼ï¼ä¹ä¸è¦æ key æäº¤è¿ä»»ä½ä»åºæä»¶ã |
| | | |
| | |
| | | |
| | | $ErrorActionPreference = 'Stop' |
| | | $root = Split-Path -Parent $MyInvocation.MyCommand.Path |
| | | $pomPath = Join-Path $root 'traffic-audit-server\pom.xml' |
| | | if (-not (Test-Path $pomPath)) { throw "Missing Maven project: $pomPath" } |
| | | [xml]$pom = Get-Content -LiteralPath $pomPath -Raw -Encoding UTF8 |
| | | $productVersion = [string]$pom.project.version |
| | | if (-not $productVersion) { throw 'Missing <version> in traffic-audit-server\pom.xml' } |
| | | if ($productVersion -match '(?i)-SNAPSHOT$') { throw "Release builds must not use a SNAPSHOT version: $productVersion" } |
| | | if (-not $OutRoot) { $OutRoot = Join-Path $root 'deploy' } # é»è®¤è¾åºå°ä»åº deploy\ï¼å·² gitignoreï¼ |
| | | $tplDir = Join-Path $root 'deploy-templates' # æå
模æ¿ä»¶ï¼å·²å
¥åºï¼ |
| | | $tplJarCfg = Join-Path $tplDir 'jar-application.yml' # è¿ jar çå ä½ç¬¦é
ç½® |
| | | $srcCfg = Join-Path $root 'traffic-audit-server\src\main\resources\application.yml' |
| | | $jarRel = 'traffic-audit-server\target\traffic-audit-server-1.0.0-SNAPSHOT.jar' |
| | | $jarRel = 'traffic-audit-server\target\traffic-audit-server.jar' |
| | | $jar = Join-Path $root $jarRel |
| | | $webDist = Join-Path $root 'traffic-audit-web\dist' |
| | | |
| | |
| | | $sr = New-Object System.IO.StreamReader($entry.Open()) |
| | | $text = $sr.ReadToEnd() |
| | | $sr.Close() |
| | | |
| | | $versionEntry = $zip.Entries | Where-Object { $_.FullName -eq 'BOOT-INF/classes/app-version.properties' } |
| | | if (-not $versionEntry) { throw 'jar å
ç¼ºå° BOOT-INF/classes/app-version.properties' } |
| | | $vr = New-Object System.IO.StreamReader($versionEntry.Open()) |
| | | $versionText = $vr.ReadToEnd() |
| | | $vr.Close() |
| | | |
| | | $manifestEntry = $zip.Entries | Where-Object { $_.FullName -eq 'META-INF/MANIFEST.MF' } |
| | | if (-not $manifestEntry) { throw 'jar å
ç¼ºå° META-INF/MANIFEST.MF' } |
| | | $mr = New-Object System.IO.StreamReader($manifestEntry.Open()) |
| | | $manifestText = $mr.ReadToEnd() |
| | | $mr.Close() |
| | | } finally { $zip.Dispose() } |
| | | |
| | | function Get-SecretHits([string]$ymlText) { |
| | |
| | | Write-Host ' è¦åï¼jar å
ç½® password 䏿¯ TRAFFIC_DB_PASSWORD å ä½ç¬¦å½¢å¼ï¼è¯·ç¡®è®¤æ¨¡æ¿ã' |
| | | } |
| | | Write-Host ' éè¿ï¼jar å
ç½®é
ç½®å
¨é¨ä¸ºå ä½ç¬¦ï¼æ ææå¯é¥/å£ä»¤ã' |
| | | |
| | | $builtVersion = '' |
| | | if ($versionText -match '(?m)^\s*version\s*=\s*(.+?)\s*$') { $builtVersion = $matches[1].Trim() } |
| | | if ($builtVersion -ne $productVersion) { |
| | | throw "çæ¬ä¸ä¸è´ï¼pom.xml=$productVersion, app-version.properties=$builtVersion" |
| | | } |
| | | |
| | | $manifestVersion = '' |
| | | if ($manifestText -match '(?m)^Implementation-Version:\s*(.+?)\s*$') { $manifestVersion = $matches[1].Trim() } |
| | | if ($manifestVersion -ne $productVersion) { |
| | | throw "çæ¬ä¸ä¸è´ï¼pom.xml=$productVersion, MANIFEST.MF=$manifestVersion" |
| | | } |
| | | Write-Host " çæ¬èªæ£éè¿ï¼$productVersion (pom / app-version.properties / MANIFEST.MF)" |
| | | |
| | | # ---------- [3/5] å端æå»º ---------- |
| | | # å端å£é¨ç½²å¿
é¡»æ backend\webï¼æä»¥å³ä½¿ -NoFrontendDist ä¹éè¦ distï¼åªæ -SkipFrontend æå¤ç¨ç°æ distã |
| | |
| | | # ---------- [4/5] ç»è£
宿´é¨ç½²ç®å½ ---------- |
| | | Write-Host '[4/5] ç»è£
é¨ç½²ç®å½...' |
| | | $stamp = Get-Date -Format 'yyyyMMdd' |
| | | $dest = Join-Path $OutRoot ("traffic-audit-deploy-" + $stamp) |
| | | $dest = Join-Path $OutRoot ("traffic-audit-deploy-" + $stamp + "-v" + $productVersion) |
| | | $n = 2 |
| | | while (Test-Path $dest) { $dest = Join-Path $OutRoot ("traffic-audit-deploy-" + $stamp + "-" + $n); $n++ } |
| | | while (Test-Path $dest) { $dest = Join-Path $OutRoot ("traffic-audit-deploy-" + $stamp + "-v" + $productVersion + "-" + $n); $n++ } |
| | | if ($NoFrontendDist) { |
| | | New-Item -ItemType Directory -Force -Path (Join-Path $dest 'backend'), (Join-Path $dest 'db') | Out-Null |
| | | } else { |
| | |
| | | |
| | | # READMEï¼ç¨æ¨¡æ¿å¹¶æ¿æ¢æ¥æå ä½ |
| | | $readme = Get-Content (Join-Path $tplDir 'README-é¨ç½²è¯´æ.txt') -Raw -Encoding UTF8 |
| | | $readme = $readme.Replace('{stamp}', $stamp) |
| | | $readme = $readme.Replace('{stamp}', $stamp).Replace('{version}', $productVersion) |
| | | Set-Content -LiteralPath (Join-Path $dest 'README-é¨ç½²è¯´æ.txt') -Value $readme -Encoding UTF8 |
| | | |
| | | # ---------- [5/5] æ´å
ææå¯é¥æ«æ + æ±æ» ---------- |
| | |
| | | """TrafficAudit ä¸é®æå
èæ¬ï¼å端æå»º -> å
åµè¿å端 jar -> ç»è£
é¨ç½²å
-> æ zip |
| | | ç¨æ³ï¼python package-deploy.py [--no-build] |
| | | """ |
| | | import io, os, sys, shutil, zipfile, subprocess, datetime |
| | | import io, os, sys, shutil, zipfile, subprocess, datetime, xml.etree.ElementTree as ET |
| | | |
| | | ROOT = os.path.dirname(os.path.abspath(__file__)) |
| | | WEB = os.path.join(ROOT, "traffic-audit-web") |
| | | SERVER = os.path.join(ROOT, "traffic-audit-server") |
| | | STATIC = os.path.join(SERVER, "src", "main", "resources", "static") |
| | | _pom_tree = ET.parse(os.path.join(SERVER, "pom.xml")) |
| | | _pom_ns = {"m": "http://maven.apache.org/POM/4.0.0"} |
| | | PRODUCT_VERSION = (_pom_tree.getroot().findtext("m:version", namespaces=_pom_ns) or "").strip() |
| | | if not PRODUCT_VERSION: |
| | | raise SystemExit("Missing <version> in traffic-audit-server/pom.xml") |
| | | STAMP = datetime.datetime.now().strftime("%Y%m%d") |
| | | STAGE = os.path.join(ROOT, "deploy", "traffic-audit-deploy-" + STAMP) |
| | | ZIP = os.path.join(ROOT, "traffic-audit-deploy-" + STAMP + ".zip") |
| | | JAR_NAME = "traffic-audit-server-1.0.0-SNAPSHOT.jar" |
| | | STAGE = os.path.join(ROOT, "deploy", "traffic-audit-deploy-" + STAMP + "-v" + PRODUCT_VERSION) |
| | | ZIP = os.path.join(ROOT, "traffic-audit-deploy-" + STAMP + "-v" + PRODUCT_VERSION + ".zip") |
| | | JAR_NAME = "traffic-audit-server.jar" |
| | | SKIP_DOC_DIRS = {"ai_demo", "usage_screenshots", "åè½æµè¯æ¥å", "工使¥ç»"} |
| | | |
| | | def rmtree_force(path): |
| | |
| | | io.open(os.path.join(be, "start-backend.cmd"), "w", encoding="utf-8", newline="\r\n").write(START_CMD) |
| | | io.open(os.path.join(be, "start-backend.sh"), "w", encoding="utf-8", newline="\n").write(START_SH) |
| | | io.open(os.path.join(STAGE, "frontend", "nginx.conf.example"), "w", encoding="utf-8", newline="\n").write(NGINX) |
| | | io.open(os.path.join(STAGE, "README-é¨ç½²è¯´æ.txt"), "w", encoding="utf-8", newline="\r\n").write(README) |
| | | io.open(os.path.join(STAGE, "README-é¨ç½²è¯´æ.txt"), "w", encoding="utf-8", newline="\r\n").write(README.replace("{version}", PRODUCT_VERSION)) |
| | | |
| | | print("[5/6] æ zip ...") |
| | | if os.path.isfile(ZIP): |
| | |
| | | echo å端已å
åµï¼ç´æ¥è®¿é® 8090 å³å¯ï¼ä¸éè¦ nginxï¼ |
| | | echo æ¥å¿æ¾ç¤ºå¨æ¬çªå£ï¼å
³éçªå£å³åæ¢æå¡ |
| | | echo ============================================ |
| | | java -jar traffic-audit-server-1.0.0-SNAPSHOT.jar |
| | | java -jar traffic-audit-server.jar |
| | | pause |
| | | """ |
| | | |
| | | START_SH = u"""#!/bin/sh |
| | | cd "$(dirname "$0")" || exit 1 |
| | | echo "TrafficAudit å¯å¨ä¸ï¼http://localhost:8090 ï¼Ctrl+C 忢ï¼" |
| | | java -jar traffic-audit-server-1.0.0-SNAPSHOT.jar 2>&1 | tee app.log |
| | | java -jar traffic-audit-server.jar 2>&1 | tee app.log |
| | | """ |
| | | |
| | | NGINX = u"""# å端 nginx é
置示ä¾ï¼åªæå¨ä¸æ³ç¨ãjar å
åµåç«¯ãæ¶æéè¦ï¼ |
| | |
| | | } |
| | | """ |
| | | |
| | | README = u"""TrafficAudit 交éè´§è¿ç»è®¡å®¡æ ¸ç³»ç» ââ é¨ç½²å
ï¼{stamp}ï¼ |
| | | README = u"""TrafficAudit 交éè´§è¿ç»è®¡å®¡æ ¸ç³»ç» ââ é¨ç½²å
ï¼{stamp}ï¼çæ¬ v{version}ï¼ |
| | | ======================================================== |
| | | |
| | | ãç®å½ç»æã |
| | | backend/ |
| | | traffic-audit-server-1.0.0-SNAPSHOT.jar å端ç¨åºï¼å«å
¨é¨ä¾èµï¼**å·²å
åµå端**ï¼ |
| | | traffic-audit-server.jar å端ç¨åºï¼å«å
¨é¨ä¾èµï¼**å·²å
åµå端**ï¼åºå®æä»¶åï¼ |
| | | docs/ æ¥è¡¨æ¨¡æ¿ä¸è¿è¡æ°æ®ç®å½ï¼å¿
éï¼å¿å ï¼ |
| | | application.yml å¤é¨é
ç½®ï¼æ¹è¿éå³å¯ï¼æ ééæ°æå
ï¼ |
| | | start-backend.cmd / start-backend.sh å¯å¨èæ¬ |
| | |
| | | </parent> |
| | | <groupId>com.trafficaudit</groupId> |
| | | <artifactId>traffic-audit-server</artifactId> |
| | | <version>1.0.0-SNAPSHOT</version> |
| | | <version>1.0.0</version> |
| | | <packaging>jar</packaging> |
| | | <name>traffic-audit-server</name> |
| | | <properties> |
| | |
| | | </dependency> |
| | | </dependencies> |
| | | <build> |
| | | <finalName>traffic-audit-server</finalName> |
| | | <resources> |
| | | <resource> |
| | | <directory>src/main/resources</directory> |
| | | <filtering>false</filtering> |
| | | <excludes> |
| | | <exclude>app-version.properties</exclude> |
| | | </excludes> |
| | | </resource> |
| | | <resource> |
| | | <directory>src/main/resources</directory> |
| | | <filtering>true</filtering> |
| | | <includes> |
| | | <include>app-version.properties</include> |
| | | </includes> |
| | | </resource> |
| | | </resources> |
| | | <plugins> |
| | | <plugin> |
| | | <groupId>org.apache.maven.plugins</groupId> |
| | | <artifactId>maven-jar-plugin</artifactId> |
| | | <configuration> |
| | | <archive> |
| | | <manifest> |
| | | <addDefaultImplementationEntries>true</addDefaultImplementationEntries> |
| | | </manifest> |
| | | </archive> |
| | | </configuration> |
| | | </plugin> |
| | | <plugin> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-maven-plugin</artifactId> |
| | | </plugin> |
| | |
| | | .authorizeRequests() |
| | | // ç»å½åå¿
é¡»å¯ç¨çæ¥å£ |
| | | .antMatchers("/api/auth/login", "/api/auth/captcha", "/api/auth/captcha/verify", |
| | | "/api/auth/captcha-config").permitAll() |
| | | "/api/auth/captcha-config", "/api/version").permitAll() |
| | | // å端éæèµæº |
| | | .antMatchers("/", "/index.html", "/favicon.ico", "/js/**", "/css/**", "/fonts/**", "/img/**", "/static/**").permitAll() |
| | | .anyRequest().permitAll() |
| | |
| | | .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); |
| | | return http.build(); |
| | | } |
| | | } |
| | | } |
| | |
| | | "/api/auth/login", |
| | | "/api/auth/captcha", |
| | | "/api/auth/captcha/verify", |
| | | "/api/auth/captcha-config" |
| | | "/api/auth/captcha-config", |
| | | "/api/version" |
| | | ); |
| | | |
| | | @Resource |
| | |
| | | request.setAttribute("loginUser", username); |
| | | chain.doFilter(request, response); |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | package com.trafficaudit.system.controller; |
| | | |
| | | import com.trafficaudit.common.Result; |
| | | import org.springframework.core.io.ClassPathResource; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.io.InputStream; |
| | | import java.net.URI; |
| | | import java.nio.file.Files; |
| | | import java.nio.file.Path; |
| | | import java.nio.file.Paths; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.Map; |
| | | import java.util.Properties; |
| | | |
| | | /** |
| | | * Exposes the product version so the UI (and operators) can confirm which build |
| | | * is actually running on a server. Kept public on purpose: the login page shows |
| | | * the version before any token exists. |
| | | */ |
| | | @RestController |
| | | @RequestMapping("/api") |
| | | public class VersionController { |
| | | |
| | | private static final String VERSION_FILE = "app-version.properties"; |
| | | |
| | | @GetMapping("/version") |
| | | public Result<Map<String, Object>> version() { |
| | | Map<String, Object> info = new LinkedHashMap<>(); |
| | | info.put("version", readVersion()); |
| | | info.put("buildTime", resolveBuildTime()); |
| | | return Result.ok(info); |
| | | } |
| | | |
| | | private String readVersion() { |
| | | try (InputStream in = new ClassPathResource(VERSION_FILE).getInputStream()) { |
| | | Properties props = new Properties(); |
| | | props.load(in); |
| | | String value = props.getProperty("version"); |
| | | return value == null || value.trim().isEmpty() ? "unknown" : value.trim(); |
| | | } catch (Exception e) { |
| | | return "unknown"; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Build time of the running artifact. In a packaged run this is the jar file's |
| | | * last-modified time; when running from exploded classes (mvn spring-boot:run) |
| | | * there is no jar, so the value is null. |
| | | */ |
| | | private String resolveBuildTime() { |
| | | try { |
| | | URI location = VersionController.class.getProtectionDomain() |
| | | .getCodeSource().getLocation().toURI(); |
| | | Path path = resolveArtifactPath(location); |
| | | if (path != null && Files.isRegularFile(path)) { |
| | | return Files.getLastModifiedTime(path).toInstant().toString(); |
| | | } |
| | | } catch (Exception ignored) { |
| | | // Fall through: build time is optional information. |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * Spring Boot executable jars expose a nested classpath such as |
| | | * "jar:file:/app.jar!/BOOT-INF/classes!/". Strip the nested part before |
| | | * asking the filesystem for the jar timestamp. |
| | | */ |
| | | private Path resolveArtifactPath(URI location) { |
| | | String value = location.toString(); |
| | | int nested = value.indexOf("!/"); |
| | | if (nested >= 0) { |
| | | value = value.substring(0, nested); |
| | | } |
| | | if (value.startsWith("jar:")) { |
| | | value = value.substring(4); |
| | | } |
| | | return Paths.get(URI.create(value)); |
| | | } |
| | | } |
| New file |
| | |
| | | # Supplied from pom.xml during Maven resource filtering. |
| | | # Bump <version> in pom.xml on every release; do not hard-code a version here. |
| | | version=@project.version@ |
| | |
| | | <template> |
| | | <el-header class="app-header"> |
| | | <span class="header-title">{{ title }}</span> |
| | | <span class="header-title"> |
| | | {{ systemName }}<span class="header-version" v-if="version">V{{ version }}</span> |
| | | <template v-if="pageName"> - {{ pageName }}</template> |
| | | </span> |
| | | <div class="header-right"> |
| | | <span class="header-user"> |
| | | <i class="el-icon-user"></i> {{ username }} |
| | |
| | | }, |
| | | data() { |
| | | return { |
| | | version: '', |
| | | pwdDialogVisible: false, |
| | | pwdSaving: false, |
| | | pwdForm: { oldPassword: '', newPassword: '', confirmPassword: '' }, |
| | |
| | | computed: { |
| | | username() { |
| | | return sessionStorage.getItem('username') || 'admin' |
| | | }, |
| | | // The system name always comes first so the version can sit right after it. |
| | | systemName() { |
| | | return this.title.split(' - ')[0] |
| | | }, |
| | | pageName() { |
| | | const parts = this.title.split(' - ') |
| | | return parts.length > 1 ? parts.slice(1).join(' - ') : '' |
| | | } |
| | | }, |
| | | created() { |
| | | api.get('/version') |
| | | .then(res => { |
| | | if (res && res.data && res.data.version) this.version = res.data.version |
| | | }) |
| | | .catch(() => {}) |
| | | }, |
| | | methods: { |
| | | openChangePwd() { |
| | |
| | | line-height: normal; |
| | | } |
| | | .header-user { opacity: 0.92; } |
| | | .header-version { |
| | | font-size: 12px; |
| | | line-height: 1.6; |
| | | margin-left: 8px; |
| | | padding: 2px 8px; |
| | | border-radius: 8px; |
| | | background: rgba(255, 255, 255, 0.18); |
| | | } |
| | | .header-link { color: #fff; font-size: 14px; padding: 0; } |
| | | .header-link:hover { color: #ffd04b; } |
| | | .header-logout { color: #fff; font-size: 14px; padding: 0; } |
| | |
| | | <template> |
| | | <div class="login-container"> |
| | | <el-card class="login-card"> |
| | | <h2>交éç»è®¡æ¥è¡¨å®¡æ ¸ç³»ç»</h2> |
| | | <h2>交éç»è®¡æ¥è¡¨å®¡æ ¸ç³»ç»<span class="login-version" v-if="version">V{{ version }}</span></h2> |
| | | <el-form ref="form" :model="form" :rules="rules"> |
| | | <el-form-item prop="username"> |
| | | <el-input v-model="form.username" placeholder="ç¨æ·å" @keyup.enter.native="login"></el-input> |
| | |
| | | captchaId: '', |
| | | clickIds: [], |
| | | loggingIn: false, |
| | | captchaRequired: false |
| | | captchaRequired: false, |
| | | version: '' |
| | | } |
| | | }, |
| | | created() { |
| | | axios.get('/api/version', { timeout: 10000 }) |
| | | .then(res => { |
| | | const d = res.data |
| | | if (d && d.data && d.data.version) this.version = d.data.version |
| | | }) |
| | | .catch(() => {}) |
| | | // éªè¯ç æ¯å¦å¯ç¨ä¸å¾ä»¥å端 /api/auth/captcha-config 为åï¼ |
| | | // é»è®¤ä¸æ¾ç¤ºï¼åªæå端æç¡®è¿å required=true ææ¸²æéªè¯ç ç»ä»¶ã |
| | | // ä¿®å¤ï¼æ¤åé»è®¤ true ä¸è¯·æ±å¤±è´¥æ¶éé»å¿½ç¥ï¼åæ¢ç½ç»å该é
置读ä¸å°ï¼ |
| | |
| | | .captcha-skip-tip { font-size: 12px; color: #909399; line-height: 1.6; padding: 8px 10px; background: #F5F7FA; border-radius: 4px; } |
| | | .login-card { width: 400px; } |
| | | .login-card h2 { text-align: center; margin-bottom: 18px; } |
| | | .login-version { font-size: 13px; font-weight: normal; color: #909399; margin-left: 8px; vertical-align: 3px; } |
| | | .login-card .el-form-item { margin-bottom: 16px; } |
| | | </style> |