| .gitignore | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| docs/功能测试报告/功能测试报告_部署包打包与独立启动_2026-09-13.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| docs/工作日结/工作日结_2026-09-13.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| docs/打包部署说明.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| package-deploy.py | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| traffic-audit-server/src/main/java/com/trafficaudit/security/utils/JwtUtils.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
.gitignore
@@ -67,3 +67,9 @@ # ==== packaged static dir (copied from dist, not committed) ==== web/ traffic-audit-server/web/ # ==== é¨ç½²äº§ç©ï¼ä¸å ¥åºï¼==== deploy/ traffic-audit-deploy-*.zip _t_wyc_aug.docx _deploytest/ docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_²¿Êð°ü´ò°üÓë¶ÀÁ¢Æô¶¯_2026-09-13.md
New file @@ -0,0 +1,91 @@ # åè½æµè¯æ¥å_é¨ç½²å æå ä¸ç¬ç«å¯å¨_2026-09-13 ## ä¸ãåè½è¯´æ ç¨æ·éè¦æç³»ç»æå é¨ç½²å°å¦ä¸å°æºå¨ãæ¬è½®äº¤ä»ä¸ä»¶äºï¼ ### 1. ä¸é®æå èæ¬ `package-deploy.py`ï¼æ°å¢ï¼ 䏿¡å½ä»¤å®æï¼å端æå»º â æ `dist` å åµè¿å端 jarï¼æ·è¿ `src/main/resources/static`ï¼â `mvn clean package` â æ¸ 空 staticï¼ä¿æä»åºå¹²åï¼â ç»è£ é¨ç½²ç®å½ â å缩 zipã 产ç©ï¼ - ç®å½ `deploy/traffic-audit-deploy-YYYYMMDD/` - å缩å `traffic-audit-deploy-YYYYMMDD.zip`ï¼æ¬æ¬¡ 69.9 MB / 246 个æä»¶ï¼ é¨ç½²ç®å½ç»æï¼æ²¿ç¨ 8 æçå ä¹ æ¯ï¼ï¼ ``` backend/ jarï¼å«å åµå端ï¼+ docs/ + application.yml + start-backend.cmd/.sh frontend/ dist/ + nginx.conf.example ï¼ä» nginx æ¹æ¡éè¦ï¼ db/ init.sql + sql_city_bus.sql + sql_city_taxi.sql + sql_wyc.sql README-é¨ç½²è¯´æ.txt ``` ### 2. ä¿®å¤ `JwtUtils`ï¼`jwt.secret` éæ³ Base64 导è´ç»å½ 500ï¼æ ¹å ä¿®å¤ï¼ - ç°è±¡ï¼æ¬æ¬¡çæµå®æµï¼ï¼æå¤ç½® `application.yml` ç `jwt.secret` å¡«æä¸æä¸²åï¼ç»å½æ¥å£è¿å `500 {"code":500,"message":"20018"}`ã - æ ¹å ï¼jjwt 0.9.1 é»è®¤æ secret å½ **Base64** è§£ç ï¼éæ³å符ä¼å¨ `DatatypeConverter.guessLength` æ `ArrayIndexOutOfBoundsException`ï¼è¢« `GlobalExceptionHandler` å æ 500ãé¨ç½²åäºç¬¬ä¸æ¬¡æ¹é ç½®å¾å®¹æè¸©ã - å¤ç½®ï¼`JwtUtils` æ°å¢ `secretKeyBytes()`ââè½æ Base64 è§£ç å°±ç¨è§£ç ç»æï¼ä¸åå² token å ¼å®¹ï¼ï¼å¦åæ UTF-8 åèå¤çå¹¶æ WARNã ### 3. æ´æ£ãæå é¨ç½²è¯´æãï¼`docs/æå é¨ç½²è¯´æ.md`ï¼ æ§çï¼2026-08-27ï¼æä¸å¤ä¸ç°ç¶ä¸ç¬¦ï¼æ¬æ¬¡ä¸å¹¶æ¹æ£ï¼ | æ§è¯´æ | å®é æ åµ | å¤ç | |--------|----------|------| | ãRedis å端å¯å¨å¿ éã | pom æ redis ä¾èµï¼ä»£ç 乿ªä½¿ç¨ | æ¹ä¸ºãä¸éè¦ Redisãï¼å¹¶å»æå¤ç½®é ç½®éç redis 段 | | ãjar å·²å ç½®åç«¯éææç®¡ï¼file:./web/ï¼ã | jar å æ ä»»ä½éææä»¶ï¼ä¹æ²¡æ `static-locations` é ç½®ï¼æ§å å®é é nginx | æ¹ä¸ºãæå æ¶æ dist å åµè¿ jarãï¼è®¿é® 8090 å³å¯ï¼æ é nginx | | æ°æ®åºåªæ 3 ä¸ªèæ¬ | ç°ç½è¿æ `wyc_total_monthly` / `wyc_order_monthly` ä¸¤å¼ è¡¨ | è¡¥ `db/sql_wyc.sql`ï¼å¹¶è¡¥å `summary.template-dir` çé ç½®ä¸æ¶åº | ## äºãæµè¯ç¯å¢ - å¼åæºï¼å端 8090ï¼`start-dev.ps1`ï¼éå¯å PID ååï¼ãå端 8080ãMySQL 127.0.0.1:3308ã - é¨ç½²å éªè¯ï¼æ `deploy/traffic-audit-deploy-20260913/backend` æ·å° `_deploytest/`ï¼ç¨ **8091** 端å£ç¬ç«å¯å¨ ï¼æ°æ®åºç¨å½ä»¤è¡åæ°è¦ç为 3308ï¼æ¨¡æãå¤ç½® yml + å½ä»¤è¡è¦çãä¸¤ç§æ¹é ç½®æ¹å¼ï¼ã - æµè¯æ¶é´ï¼2026-09-13ï¼èæ¬ï¼`package-deploy.py`ã`_deploy_smoke.py`ï¼ç»æ `_deploytest_result.txt`ã`_deploytest_backend.log`ï¼ã ## ä¸ãç¨ä¾è¡¨ ### 3.1 æ£åç¨ä¾ | ç¼å· | è¾å ¥ | 颿 | å®é | ç»è®º | | --- | --- | --- | --- | --- | | TC-1 | `python package-deploy.py --no-build` | äº§åº zipï¼ä¸æ æ¥é | `traffic-audit-deploy-20260913.zip` 69.9 MB / 246 æä»¶ | éè¿ | | TC-2 | æ£æ¥ jar å 容 | å«å åµå端 | jar 55.5 MBï¼`BOOT-INF/classes/static/` ä¸ 42 个æä»¶ï¼`static/index.html` åå¨ | éè¿ | | TC-3 | æ£æ¥é¨ç½²ç®å½ç»æ | backend/frontend/db/README é½å ¨ | backendï¼jar + docs + application.yml + 2 个å¯å¨èæ¬ï¼ãfrontend/distãdb 4 个 sqlãREADME | éè¿ | | TC-4 | æå åæºç ç®å½ | `src/main/resources/static` åºè¢«æ¸ 空 | æå ç»æèªå¨æ¸ 空ï¼ä»åºæ 污æï¼ | éè¿ | | TC-5 | ä»é¨ç½²å ç¬ç«å¯å¨ï¼8091ï¼ | å¯å¨æå | æ¥å¿åºç° `Started TrafficAuditApplication`ã`Tomcat started on port(s): 8091` | éè¿ | | TC-6 | `GET /` | 200 ä¸è¿åé¡µé¢ | 200ï¼1828 åèï¼å« `<div id="app">` | éè¿ | | TC-7 | `GET /js/app.*.js` | 200ï¼éæèµæºå¯è®¿é®ï¼ | 200ï¼6253 åè | éè¿ | | TC-8 | `POST /api/auth/login`ï¼admin/123456ï¼ | 200 ä¸è¿å token | 200ï¼`{"code":200,"message":"success","data":{...,"token":"eyJ..."}}` | éè¿ | | TC-9 | 带 token 导åºãéè·¯è¿è¾éæ±æ»è¡¨ã2026-08 | 200 䏿¯åæ³ xlsx | 200ï¼950,783 åèï¼å¤´é¨ `PK`ï¼ä¸å¼åæºå¯¼åºä»¶åå°ºå¯¸ï¼ | éè¿ | ### 3.2 è´åç¨ä¾ | ç¼å· | è¾å ¥ | 颿 | å®é | ç»è®º | | --- | --- | --- | --- | --- | | TC-N1 | ä¿®å¤åï¼`--jwt.secret=è¿æ¯ä¸ä¸ªä¸æå¯é¥` | æ´é²é®é¢ | ç»å½ 500ï¼æ¥å¿ `ArrayIndexOutOfBoundsException: 20018 at JwtUtils.generateToken` | å·²å¤ç°ï¼é®é¢æç«ï¼ | | TC-N2 | ä¿®å¤åï¼åæ ·ä¼ ä¸æ secret | ä¸å å¯é¥æ ¼å¼å´©ï¼ç»å½ä»å¯ç¨ | ç»å½ 200 æ¿å° tokenï¼å¯¼åºåæ · 200 / 950,783 åèï¼æ¥å¿åºç°ãjwt.secret 䏿¯åæ³ç Base64 å符串â¦ãWARN | éè¿ | | TC-N3 | å¤ç½® application.yml ä¿çå ä½å¯ç ï¼ç¨å½ä»¤è¡ `--spring.datasource.password` è¦ç | å½ä»¤è¡è¦ççæ | å¯å¨æåå¹¶æ£å¸¸æ¥åºï¼ç»å½ 200ï¼ | éè¿ | | TC-N4 | æå èæ¬é夿§è¡ï¼æ§ staging ç®å½å«åªè¯»æä»¶ï¼ | è½æ¸ çå¹¶é建 | é¦è½®æ¥ `PermissionError WinError 5`ï¼å `rmtree_force`ï¼å æ¸ åªè¯»å±æ§ï¼åæ£å¸¸ | å·²ä¿®å¤ | ### 3.3 åå½ç¨ä¾ | ç¼å· | è¾å ¥ | 颿 | å®é | ç»è®º | | --- | --- | --- | --- | --- | | TC-R1 | å¼åæºéå¯å端ï¼è½½å ¥ JwtUtils æ¹å¨ï¼ | åè½ä¸åå½ | ç»å½ 200ï¼å¯¼åº 2026-08 â HTTP 200 / 950,783 åèï¼ä¸é¨ç½²å 产ç©ã9-13 彿¡£ä»¶åå°ºå¯¸ï¼ | éè¿ | | TC-R2 | å端ç产æå»º | æå»ºæå | `npm run build` æåï¼`dist/index.html` + css/js/fonts é½å ¨ | éè¿ | ## åãåç°çé®é¢ä¸å¤ç½® 1. **`jwt.secret` éæ³ Base64 â ç»å½ 500**ï¼çæµæå°ï¼ï¼å·²ææ ¹å ä¿®å¤ï¼Base64 ä¼å ãå¦å UTF-8 å åº + WARNï¼ï¼å¹¶å¨æå é ç½®éç»åºå¯ç´æ¥ä½¿ç¨ç 32 ä½åå è¿å¶ç¤ºä¾å¼ãå¨è¯´æææ¡£éåæåå¼è§åã 2. **æå èæ¬æ¸ çæ§ç®å½è¢«åªè¯»æä»¶æ¡ä½**ï¼æº `docs` éæåªè¯» xlsxï¼`copy2` 伿åªè¯»å±æ§å¸¦è¿å»ï¼å¯¼è´ Windows ä¸ `rmtree` æ¥ãæç»è®¿é®ãâ æ°å¢ `rmtree_force()` å `chmod` åå ã 3. **æ§ãæå é¨ç½²è¯´æãä¸å¤ä¸å®**ï¼Redis å¿ é / jar å·²å ç½®å端 / 缺 sql_wyc.sqlï¼ï¼å·²å ¨é¨æ´æ£ï¼å¹¶è¡¥ä¸é¨ç½²åéªè¯æ¸ åä¸å¸¸è§é®é¢ã 4. 说æï¼çæµèæ¬éãæ¿å° tokenãé£ä¸é¡¹æå°ä¸º Falseï¼æ¯èæ¬æååºä½æªæå° 120 å符åå夿å符串导è´ï¼æªæåçä¸å° `"token"`ï¼ï¼åå§ååºä¸åç»å¸¦ token ç导åºè¯·æ±åæåï¼HTTP 200ï¼ï¼ç¨åºæ¬èº«æ é®é¢ã ## äºãç»è®º - æå èæ¬ä¸é®å¯äº§åºå¯ç´æ¥é¨ç½²ç zipï¼é¨ç½²å å¨**è±ç¦»æºç ç®å½**ãä» é jar + docs + å¤ç½®é ç½®çåæä¸ï¼ç¬ç«å¯å¨ã页é¢/éæèµæº/ç»å½/导åºå ¨é¨éè¿ï¼å¯¼åºäº§ç©ä¸å¼åæºä¸è´ï¼950,783 åèï¼ã - `jwt.secret` çé¨ç½²é·é±å·²æ ¹å ä¿®å¤ï¼é¨ç½²åäºå³ä½¿å¡«äºä¸è§èçå¼ä¹ä¸ä¼ååºç°ãç»å½ 500ãèæ ä»ä¸æã - é¨ç½²è¯´æå·²ä¸å½å代ç 对é½ï¼ä¸éè¦ Redisãä¸éè¦ nginxã4 ä¸ªå»ºè¡¨èæ¬ãå¤ç½®é 置项é½å ¨ï¼ã docs/¹¤×÷ÈÕ½á/¹¤×÷ÈÕ½á_2026-09-13.md
@@ -39,6 +39,16 @@ - æ¨éå `git fetch gitea` / `git fetch origin` åæ æ°æäº¤ï¼`rev-list --left-right --count` = `0 0`ï¼ï¼æªè¦çåäºä»£ç ã - åå¸åå¤è· 2026-08 导åºï¼HTTP 200 / 950,783 åè / 29.2 ç§ï¼ï¼å¯¹åå¸åäº§ç© `_t4_2026-08.xlsx` åå 586 æ ¼ç¬ç«å¤æ ¸ = å·®å¼ 0 æ ¼ï¼ä¸åå¸å产ç©é zip æ¡ç®æ¯å¯¹ï¼å 鍿¡ç®åèå®å ¨ä¸è´ï¼MD5 å·®å¼ä» æ¥èª zip 头æ¶é´æ³ï¼ã ### 8. æå é¨ç½²æ¯æï¼ç¨æ·æ°éæ±ï¼é¨ç½²å°å¦ä¸å°æºå¨ï¼ - æ°å¢ä¸é®æå èæ¬ `package-deploy.py`ï¼å端 `npm run build` â `dist` å åµè¿å端 jarï¼æ·å ¥ `resources/static`ï¼â `mvn clean package` â æ¸ 空 static â ç»è£ `deploy/traffic-audit-deploy-YYYYMMDD/` â å缩 `traffic-audit-deploy-YYYYMMDD.zip`ï¼æ¬æ¬¡ 69.9 MB / 246 æä»¶ï¼jar 55.5 MBï¼ã - é¨ç½²å ç»æï¼`backend/`ï¼jar + docs + application.yml + start-backend.cmd/.shï¼ã`frontend/`ï¼dist + nginx 示ä¾ï¼ã`db/`ï¼init.sql + sql_city_bus/taxi/wyc.sqlï¼ãREADMEã - **ä¿®å¤é¨ç½²é·é±**ï¼`jwt.secret` å¡«æéæ³ Base64ï¼å¦ä¸æï¼ä¼è®©ç»å½æ¥å£ 500ï¼jjwt 0.9.1 æ Base64 è§£ç secretï¼â `JwtUtils` æ°å¢ `secretKeyBytes()` å åºï¼Base64 ä¼å ãå¦å UTF-8 åè + WARNï¼ã - æ´æ£ `docs/æå é¨ç½²è¯´æ.md` ä¸å¤ä¸å®ï¼â ä¸éè¦ Redisï¼pom æ ä¾èµãä»£ç æªç¨ï¼ï¼â¡ å端æ¹ä¸ºå åµè¿ jarï¼æ§è¯´æç§°ãå·²å ç½® file:./web/ãï¼å®é jar å æ éææä»¶ï¼ï¼â¢ è¡¥ `sql_wyc.sql` ä¸ `summary.template-dir`ã - ç¬ç«éªè¯ï¼æé¨ç½²å backend æ·å° `_deploytest/` ç¨ 8091 端å£ç¬ç«å¯å¨ â å¯å¨æåã`GET /` 200 æ `#app`ãéæ js 200ãç»å½ 200 æ¿å° tokenãå¯¼åºæ±æ»å¤§è¡¨ 200 / 950,783 åèï¼ä¸å¼åæºäº§ç©å尺寸ï¼ï¼å¦æµä¸æ secret å åºè·¯å¾åæ · 200ã - å¼åæºåç«¯å·²ææ°ä»£ç éå¯ï¼æ§ PID 27840 å·²åï¼ï¼éå¯åç»å½ 200ãå¯¼åº 950,783 åèï¼æ åå½ã - æ¥åï¼`docs/åè½æµè¯æ¥å/åè½æµè¯æ¥å_é¨ç½²å æå ä¸ç¬ç«å¯å¨_2026-09-13.md`ã ## äºãæµè¯ç»ææè¦ï¼è¯¦è§ãåè½æµè¯æ¥åãï¼ | 项 | ç»æ | docs/´ò°ü²¿Êð˵Ã÷.md
@@ -1,6 +1,6 @@ # 交éç»è®¡æ¥è¡¨å®¡æ ¸ç³»ç» â æå ä¸é¨ç½²è¯´æ > éç¨ï¼åå¹¶å main 忝ï¼2026-08-27 èµ·ï¼ãå端 Spring Boot 2.7ï¼Java 8ï¼ï¼å端 Vue 2 + Element UIã > éç¨ï¼main åæ¯ï¼ææ°æ´æ° 2026-09-13ï¼ãå端 Spring Boot 2.7ï¼Java 8ï¼ï¼å端 Vue 2 + Element UIã > æ¬ææ¡£é¢åå¼åä¸é¨ç½²åäºï¼å½ä»¤åå¨ Windows ä¸éªè¯ã ## ä¸ã项ç®ç»æ @@ -9,156 +9,161 @@ |------|------| | `traffic-audit-server` | å端ï¼Spring Bootï¼Java 8ï¼ç«¯å£ 8090ï¼æ¥å£å ¨é¨å¨ `/api/**`ï¼ | | `traffic-audit-web` | å端ï¼Vue 2 + Element UIï¼å¼åç«¯å£ 8080ï¼`/api` 代çå° 8090ï¼ | | `docs` | è¿è¡æ°æ®ç®å½ï¼æ¥è¡¨ Word/Excel æ¨¡æ¿ + ç®å½å¯¼å ¥æ°æ®ï¼ï¼**åå¸å¿ 须带ä¸** | | `docs/init.sql` | æ°æ®åºåå§åèæ¬ï¼å»ºåºå»ºè¡¨ + åå§è´¦å·ï¼ | | `docs` | è¿è¡æ°æ®ç®å½ï¼æ¥è¡¨æ¨¡æ¿ãæ±æ»å¤§è¡¨æ¯ççï¼ï¼**åå¸å¿ 须带ä¸** | | `package-deploy.py` | ä¸é®æå èæ¬ï¼å端æå»º â å åµè¿ jar â ç»è£ é¨ç½²å â æ zipï¼ | ## äºãç¯å¢è¦æ± | ç»ä»¶ | çæ¬ | ç¨é | | ç»ä»¶ | çæ¬ | 说æ | |------|------|------| | JDK | 1.8 | å端ç¼è¯ä¸è¿è¡ | | Maven | 3.x | å端æå | | Node.js | 14+ | å端æå ï¼vue-cli 4.5ï¼ | | MySQL | 8.0 | æ°æ®åºï¼åºå `traffic_audit`ï¼ | | JDK | 1.8 | é¨ç½²æºå¿ é¡»ï¼å端ç¼è¯/è¿è¡ | | MySQL | 5.7 / 8.0 | é¨ç½²æºå¿ é¡»ï¼åºå `traffic_audit` | | Maven 3.x / Node.js 14+ | â | **åªæãå¨é¨ç½²æºä¸æå ãæéè¦**ï¼ç¨ä¸é®èæ¬äº§åºçå é¨ç½²åä¸éè¦ | | Redis | **ä¸éè¦** | ä»£ç æªä½¿ç¨ Redisï¼æ§è¯´æä¸ç Redis é ç½®æ¯éç项ï¼å¯å¿½ç¥ï¼ | | nginx / IIS | **ä¸éè¦** | å端已å åµè¿ jarï¼è®¿é® 8090 å³å¯ï¼è¦åå端åç¦»æ¶ææ¯å¤é | ## ä¸ãæ°æ®åºåå§å å æ§è¡å»ºåºå»ºè¡¨èæ¬ï¼åæéå¯¼å ¥åå¸å®¢è¿æ°æ®ï¼ ```bash mysql --default-character-set=utf8mb4 -h <主æº> -P 3306 -u root -p < docs/init.sql mysql --default-character-set=utf8mb4 -h <主æº> -P 3306 -u root -p traffic_audit < docs/sql_city_bus.sql mysql --default-character-set=utf8mb4 -h <主æº> -P 3306 -u root -p traffic_audit < docs/sql_city_taxi.sql ``` - `init.sql` ä¼é建 `traffic_audit` åºå¹¶é¢ç½®åå§è´¦å·ï¼`admin / admin123`ï¼ç产ç¯å¢è¯·ç»å½åæ¹å¯ç ï¼ - `sql_city_bus.sql`ã`sql_city_taxi.sql` 为åå¸å®¢è¿ï¼å ¬äº¤/åºç§ï¼ç¤ºä¾æ°æ®ï¼æéå¯¼å ¥ ## åãæå ### 4.1 å端ï¼é¡¹ç®æ ¹ç®å½æ§è¡ï¼ ## ä¸ãæå ï¼å¨å¼åæºä¸æ§è¡ï¼æ¨èä¸é®èæ¬ï¼ ```powershell cd D:\ææ¡£\ChatGPT\traffic-audit python package-deploy.py # å ¨æµç¨ï¼å端æå»º + å端æå + ç»è£ + å缩 python package-deploy.py --no-build # è·³è¿å端æå»ºï¼dist å·²æ¯ææ°æ¶æ´å¿«ï¼ ``` èæ¬åäºä»ä¹ï¼ 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ï¼ã æå·¥çä»·å½ä»¤ï¼ä¸æ³ç¨èæ¬æ¶ï¼ï¼ ```powershell cd traffic-audit-web ; npm run build ; cd .. robocopy traffic-audit-web\dist traffic-audit-server\src\main\resources\static /E cmd /c "mvn -q clean package -DskipTests -f traffic-audit-server\pom.xml" ``` 产ç©ï¼`traffic-audit-server\target\traffic-audit-server-1.0.0-SNAPSHOT.jar`ï¼å¯æ§è¡ fat jarï¼çº¦ 57MBï¼ã > 注æï¼æå·¥æ¹å¼è·å®è®°å¾å æ `traffic-audit-server/src/main/resources/static` ä¸çå 容ï¼å¦å伿±¡ææºç ç®å½ã ### 4.2 å端ï¼`traffic-audit-web` ç®å½æ§è¡ï¼ ```powershell cd traffic-audit-web npm run build ``` 产ç©ï¼`traffic-audit-web\dist\`ï¼`index.html` + `css/js/fonts`ï¼çº¯éææä»¶ï¼ã ## äºãé¨ç½²ç®å½ç»æï¼æ¨èï¼ ## åãé¨ç½²å å 容 ``` deploy\ ââ app.jar # å端 jarï¼å¯æ¹åï¼ ââ docs\ # å¿ é¡»ï¼æ¨¡æ¿ä¸ç®å½å¯¼å ¥æ°æ®ç®å½ â ââ åå¸å®¢è¿\ â ââ å ¬è·¯æ 客\ â ââ è´§è¿\ â ââ è½è\ â ââ æèµ\ â â ââ æ¨¡æ¿\ â ââ (6æ\ 7æ\ çå¯¼å ¥æ°æ®ç®å½ï¼æé) ââ web\ # å端 dist çå 容ï¼ç±å端 8090 æç®¡ï¼ ââ index.html ââ css\ js\ fonts\ traffic-audit-deploy-YYYYMMDD/ ââ backend/ â ââ traffic-audit-server-1.0.0-SNAPSHOT.jar å端 + å åµå端ï¼çº¦ 55 MBï¼ â ââ docs/ 模æ¿ä¸è¿è¡æ°æ®ï¼å¿ éï¼å¿å ï¼ â ââ application.yml å¤é¨é ç½®ï¼æ¹è¿éå³å¯ï¼æ ééæå ï¼ â ââ start-backend.cmd / start-backend.sh å¯å¨èæ¬ ââ frontend/ â ââ dist/ å端产ç©ï¼ä» nginx æ¹æ¡éè¦ï¼ â ââ nginx.conf.example nginx é ç½®ç¤ºä¾ ââ db/ â ââ init.sql 建åºå»ºè¡¨ + é¢ç½®è´¦å·ï¼å¿ é¡»æ§è¡ï¼ â ââ sql_city_bus.sql åå¸å®¢è¿-å ¬äº¤æåº¦è¡¨ï¼å¿ é¡»æ§è¡ï¼ â ââ sql_city_taxi.sql åå¸å®¢è¿-åºç§æåº¦è¡¨/ææè¡¨ï¼å¿ é¡»æ§è¡ï¼ â ââ sql_wyc.sql ç½çº¦è½¦å ¨çæ»é/订ååå¸å·è¡¨ï¼å¿ é¡»æ§è¡ï¼ ââ README-é¨ç½²è¯´æ.txt ``` å ³é®ç¹ï¼ ## äºãç®æ æºå¨é¨ç½²æ¥éª¤ - **`docs` å¿ é¡»æ¾å¨ jar å级**ãå端è¿è¡æ¶æå¯å¨ç®å½å䏿¥æ¾ `docs`ï¼æ¥è¡¨å¯¼åºç Word 模æ¿ãå¯¼å ¥é¡µãä¸è½½æ¨¡æ¿ããç®å½å¯¼å ¥æ°æ®é½ä»è¿é读ï¼ï¼æ¾ä¸å°ä¼æ¥ãæªæ¾å°æ°æ®ç®å½ docsãæãæªæ¾å°æ¨¡æ¿æä»¶ xxxãã - 馿¬¡é¨ç½²ç´æ¥æé¡¹ç®éçæ´ä¸ª `docs` æ·è¿å»æç¨³å¦¥ï¼åç»å¯ç²¾ç®ï¼åªç模æ¿åç®å½ï¼ï¼è¯¦è§ã常è§é®é¢ãã - `application.yml` æå å¨ jar å ï¼å·²å ç½®åç«¯éææç®¡ï¼`file:./web/`ï¼ï¼é¨ç½²æºéè¦æ¹é ç½®æ¶ï¼å¯å¨ jar å级æ¾ä¸ä¸ªå¤ç½® `application.yml`ï¼å¤ç½®ä¼å 级é«äºå ç½®ï¼æ³¨æéå å«å®æ´é ç½®ï¼ï¼ææ¹å®åæå ã - å¯å¨åæµè§å¨ç´æ¥è®¿é® `http://<æå¡å¨>:8090`ï¼æ éé¢å¤ Web æå¡å¨ã ### 5.1 åå§åæ°æ®åºï¼4 ä¸ªèæ¬é½è¦æ§è¡ï¼ ## å ãå ³é®é ç½®ï¼application.ymlï¼ ```bash mysql --default-character-set=utf8mb4 -u root -p < db/init.sql mysql --default-character-set=utf8mb4 -u root -p traffic_audit < db/sql_city_bus.sql mysql --default-character-set=utf8mb4 -u root -p traffic_audit < db/sql_city_taxi.sql mysql --default-character-set=utf8mb4 -u root -p traffic_audit < db/sql_wyc.sql ``` - é¢ç½®è´¦å·ï¼`admin / admin123`ï¼ç»å½å请ç«å³æ¹å¯ç ï¼ã - æ³è¿æ°æ®ä¸èµ·æ¬ï¼å¨æºæºå¨ `mysqldump -u root -p --databases traffic_audit > traffic_audit_full.sql`ï¼å¨ç®æ æºå¨ `mysql -u root -p < traffic_audit_full.sql`ï¼ä¼è¦çé¢ç½®è´¦å·ï¼ã ### 5.2 æ¹é ç½® `backend/application.yml` | é 置项 | 说æ | |--------|------| | `spring.datasource.url/username/password` | æ°æ®åºè¿æ¥ï¼æ¨¡æ¿é»è®¤ `localhost:3305/root/root`ï¼é¨ç½²æº**å¿ é¡»æ¹**ï¼ç产建议ç¨ç¯å¢åé `MYSQL_PASSWORD` æ³¨å ¥ï¼ | | `deepseek.api-key` | AI åææ¥å£å¯é¥ï¼ç¯å¢åé `DEEPSEEK_API_KEY`ï¼ä¸ä½¿ç¨ AI åæå¯çç©ºï¼ | | `jwt.secret` | ç»å½ä»¤çå¯é¥ï¼çäº§å¿ é¡»æ¹ï¼ç¯å¢åé `JWT_SECRET`ï¼ | | `docs.template-root` | å¯¼å ¥æ¨¡æ¿ä¸è½½æ ¹ç®å½ï¼é»è®¤ `docs`ï¼ | | `city-passenger.template-dir` | åå¸å®¢è¿æ¥è¡¨æ¨¡æ¿ç®å½ï¼é»è®¤ `docs/åå¸å®¢è¿`ï¼ | | `passenger.template-dir` | å ¬è·¯æ 客æ¥è¡¨æ¨¡æ¿ç®å½ï¼é»è®¤ `docs/å ¬è·¯æ 客`ï¼ | | `freight.template-dir` | è´§è¿æ¥è¡¨æ¨¡æ¿ç®å½ï¼é»è®¤ `docs/è´§è¿`ï¼ | | `energy.template-dir` | è½èæ¥è¡¨æ¨¡æ¿ç®å½ï¼é»è®¤ `docs/è½è`ï¼ | | `investment.template-dir` | æèµæ¥è¡¨æ¨¡æ¿ç®å½ï¼é»è®¤ `docs/æèµ/模æ¿`ï¼ | | `spring.datasource.url` | æ°æ®åºå°åï¼åºåå¼ `127.0.0.1:3306/traffic_audit`ï¼æå®é æ¹ï¼ | | `spring.datasource.username/password` | æ°æ®åºè´¦å·å¯ç ï¼**å¿ æ¹**ï¼ | | `jwt.secret` | ç»å½ä»¤çå¯é¥ï¼**å¿ é¡»æ¯ Base64 åæ³å符ä¸é¿åº¦æ¯ 4 çåæ°**ï¼åºå弿¯ä¸ä¸² 32 ä½åå è¿å¶ï¼ï¼å¡«ä¸ææéæ³å符ä¼å¯¼è´ç»å½ 500ï¼ç¨åºå·²åå åºå¹¶æ WARNï¼ä½ä»å»ºè®®å¡«è§èå¼ï¼ | | `deepseek.api-key` | AI åæç¨ï¼ä¸ç¨å¯ç空 | | `server.port` | é»è®¤ 8090 | > 注æï¼ä»åºåªæäº¤å 使¨¡æ¿ `application.yml.example`ï¼çå® `application.yml` ä¸å ¥åºã > å¤ç½® `application.yml` ä¸ jar å级å³çæï¼ä¼å 级é«äº jar å ç½®é ç½®ï¼ï¼æ¹å®ä¸ç¨éæ°æå ã ## ä¸ãå¯å¨å端 ### 5.3 å¯å¨ï¼å¿ é¡»å¨ `backend` ç®å½ä¸ï¼ ```powershell cd deploy java -jar app.jar # Windowsï¼åå» start-backend.cmdï¼æ cd backend ; java -jar traffic-audit-server-1.0.0-SNAPSHOT.jar ``` - æåæ å¿ï¼æ¥å¿åºç° `Started TrafficAuditApplication` å `Tomcat started on port(s): 8090`ã - å¨ `deploy` ç®å½ä¸å¯å¨å³å¯å½ä¸å级ç `docs`ã ## å «ãå端é¨ç½²ï¼æ¨èï¼Spring Boot ç´æ¥æç®¡ï¼æ é IIS/nginxï¼ - æå端æå»ºäº§ç© `dist` çå 容æ¾å° jar å级ç®å½ `web\`ï¼å³ `web\index.html`ã`web\js\`ã`web\css\`ã`web\fonts\`ï¼ã - å端已å ç½®ï¼`spring.web.resources.static-locations: file:./web/`ï¼éææç®¡ï¼+ å®å ¨é ç½®æ¾è¡éæèµæºï¼å¯å¨åç´æ¥è®¿é® `http://<æå¡å¨>:8090` å³å¯ï¼é¡µé¢ä¸ `/api` åæºï¼**ä¸éè¦ IIS/nginx å代**ã - å端路ç±ä¸º hash 模å¼ï¼å·æ°/ç´è¾¾æ 404 é®é¢ã ### å¤éï¼nginx æç®¡ + /api å代ï¼å¦éåå端åç¦»ï¼ ```nginx server { listen 80; server_name _; root D:/deploy/web; # å端 dist ç®å½ index index.html; location / { try_files $uri $uri/ /index.html; } location /api { proxy_pass http://127.0.0.1:8090; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } client_max_body_size 100m; # ä¸ä¼ Excel éè¦ï¼ä¸å端 multipart 100MB å¯¹é½ } ```bash # Linux cd backend && sh start-backend.sh ``` > è¥åç«¯ç± IIS æç®¡ï¼éå®è£ URL Rewrite 2.0 + ARR 3.0 å¹¶å¯ç¨ proxyï¼ç«ç¹æ ¹ç®å½æ¾ `docs/iis-web.config.example`ï¼éå½å web.configï¼ï¼è§å示ä¾è§è¯¥æä»¶ã æåæ å¿ï¼æ¥å¿åºç° `Started TrafficAuditApplication` ä¸ `Tomcat started on port(s): 8090`ã ## ä¹ãé¨ç½²åéªè¯ ### 5.4 è®¿é® 1. æµè§å¨æå¼ `http://<æå¡å¨>:8090`ï¼ 2. ç¨ `admin / admin123` ç»å½ï¼ç产æ¹å¯åä½¿ç¨æ°å¯ç ï¼ï¼ 3. æ°æ®å¯¼å ¥ï¼ä¸è½½æ¨¡æ¿ â ä¸ä¼ Excelï¼æç®å½å¯¼å ¥ï¼ï¼ 4. æ¥è¡¨ï¼æ¥è¯¢ â é¢è§/导åºï¼ä¾èµ `docs` æ¨¡æ¿æä»¶ï¼ï¼ 5. AI åæï¼éé ç½® `deepseek.api-key` åå¯ç¨ã æµè§å¨æå¼ `http://<é¨ç½²æºIP>:8090`ï¼å端已å åµï¼é¡µé¢ä¸æ¥å£åæºï¼æ é nginxï¼ï¼è´¦å· `admin / admin123`ã ## åã常è§é®é¢ ## å ãå ³é®é ç½®ï¼application.ymlï¼ä¸è¿è¡æ°æ® | é 置项 | é»è®¤å¼ | 说æ | |--------|--------|------| | `docs.template-root` | `docs` | å¯¼å ¥æ¨¡æ¿ä¸è½½æ ¹ç®å½ | | `city-passenger.template-dir` | `docs/åå¸å®¢è¿` | åå¸å®¢è¿ï¼å«ã模æ¿_ç½çº¦è½¦è®¢å.docxãï¼ | | `passenger.template-dir` | `docs/å ¬è·¯æ 客` | å ¬è·¯æ 客 | | `freight.template-dir` | `docs/è´§è¿` | è´§è¿ | | `energy.template-dir` | `docs/è½è` | è½è | | `investment.template-dir` | `docs/æèµ/模æ¿` | æèµ | | `summary.template-dir` | `docs/çææ±æ»å¤§è¡¨` | **æ±æ»å¤§è¡¨æ¯çä¸çå¼åç §ä»¶**ï¼å¯¼åºæ¥è¡¨ä¾èµï¼ | `docs/çææ±æ»å¤§è¡¨` è³å°è¦æï¼ - `çæ_éè·¯è¿è¾éæ±æ»è¡¨.xlsx`ï¼çå¼åç §ä»¶ï¼ç¼ºå¤±ä¼éåé»è®¤å宽ï¼ï¼ - éè¦å¯¼åºçåæä»½æ¯ç `YYYYå¹´Mæéè·¯è¿è¾éæ±æ»è¡¨.xlsx`ï¼ç¼ºåªä¸ªæï¼å¯¼é£ä¸ªæå°±ä¼æç¡®æ¥éï¼ã ## ä¸ãå端é¨ç½²ï¼ä¸¤ç§æ¹å¼ï¼ 1. **æ¨èï¼jar å åµ**ââä¸é®èæ¬å·²æ `dist` æè¿ jarï¼ç´æ¥è®¿é® `http://<IP>:8090` å³å¯ï¼æ éé¢å¤ Web æå¡å¨ã 2. å¤éï¼nginx æç®¡ `frontend/dist` å¹¶æ `/api` åä»£å° 8090ï¼é ç½®è§ `frontend/nginx.conf.example`ï¼ï¼ä¸ä¼ 100MB 大æä»¶æ¶è®°å¾è®¾ `client_max_body_size 100m`ã å端路ç±ä¸º hash 模å¼ï¼å·æ°/ç´è¾¾ä¸ä¼ 404ã ## å «ãé¨ç½²åéªè¯æ¸ å 1. `http://<IP>:8090` æå¼ç»å½é¡µï¼é¡µé¢ä¸æ¯ç©ºç½ï¼ï¼ 2. `admin / admin123` è½ç»å½ï¼å·¦ä¸è§æ¾ç¤ºã管çåãï¼ 3. ãæ°æ®å¯¼å ¥ã页è½ä¸è½½æ¨¡æ¿ãè½ä¸ä¼ Excelï¼ 4. ãæ¥è¡¨ã页æ¥è¯¢ + 导åºãéè·¯è¿è¾éæ±æ»è¡¨ãï¼è½ä¸è½½å° xlsxï¼ 5. æå¼å¯¼åºç xlsxï¼æ ¸å¯¹å½ææ°å¼æ¯å¦ä¸ºææ°æ¥è¡¨æã ## ä¹ã常è§é®é¢ | ç°è±¡ | åå / å¤ç | |------|------------| | å¯å¨æ¥ãæªæ¾å°æ°æ®ç®å½ docsã | å½åè¿è¡ç®å½ä¸å¯¹ï¼æ `docs` æ¾å° jar å级åå¯å¨ | | å¯¼åºæ¥ãæªæ¾å°æ¨¡æ¿æä»¶ xxxã | `docs` 对åºåç®å½ç¼ºæ¨¡æ¿æä»¶ï¼é¦æ¬¡é¨ç½²æ·æ´ä¸ª `docs` | | 页é¢è½å¼ä½æ¥å£ 404ï¼éªè¯ç å è½½å¤±è´¥ï¼ | åç«¯ç± IIS/nginx æç®¡æ¶æ²¡é `/api` åä»£ï¼æ¹ç¨ Spring Boot æç®¡ï¼web\ ç®å½ï¼åæ æ¤é®é¢ | | æ°æ®åºè¿æ¥å¤±è´¥ | æ£æ¥ `application.yml` å°å/è´¦å·/å¯ç ï¼å æ§è¡ `init.sql` | | ä¸ä¼ 大æä»¶å¤±è´¥ | æ£æ¥ nginx `client_max_body_size` ä¸å端 multipart éå¶ | | 端å£å ç¨ | å端 8090ãå端 80/8080 | | å¯å¨æ¥ãæªæ¾å°æ°æ®ç®å½ docsã | å¿ é¡»å¨ `backend` ç®å½ä¸å¯å¨ï¼jar ä¸ docs åçº§ï¼ | | å¯¼åºæ¥ãæªæ¾å°æ¨¡æ¿æä»¶ xxxã | `docs` 对åºåç®å½ç¼ºæ¨¡æ¿ï¼ä»æºæºå¨æ·è´ | | å¯¼åºæ¥ãæªæ¾å°æ±æ»è¡¨æ¯çãYYYYå¹´Mæâ¦ãã | `docs/çææ±æ»å¤§è¡¨` ç¼ºè¯¥ææ¯ç | | ç»å½æ¥å£ 500 | `jwt.secret` å¡«äºéæ³å符ï¼å¦ä¸æï¼ï¼æ¹æ 32 ä½åå è¿å¶ä¸² | | 页é¢è½å¼ä½æ¥å£ 404 | èµ° nginx æ¹æ¡æ¶æ²¡é `/api` åä»£ï¼æ¹ç¨ jar å åµè®¿é® 8090 | | æ°æ®åºè¿æ¥å¤±è´¥ | æ£æ¥ `application.yml`ï¼ç¡®è®¤ 4 个 SQL èæ¬å·²æ§è¡ | | 端å£å ç¨ | æ¹ `server.port`ï¼å端å¼åç«¯å£ 8080 | ## åä¸ãå¼åç¯å¢æ¥å¸¸å¯å¨ é¡¹ç®æ ¹ç®å½è¿è¡ä¸é®èæ¬ï¼èªå¨æèµ·å端 8090 + å端 8080ï¼ï¼ ## åãå¼åç¯å¢æ¥å¸¸å¯å¨ ```powershell powershell -NoProfile -ExecutionPolicy Bypass -File start-dev.ps1 ``` ``` å端 8090ï¼`mvn spring-boot:run`ï¼+ å端 8080ï¼`npm run serve`ï¼ï¼è®¿é® `http://localhost:8080`ã ## åä¸ãåæ´è®°å½ - **2026-09-13**ï¼æ°å¢ä¸é®æå èæ¬ `package-deploy.py`ï¼jar æ¹ä¸ºå åµå端ï¼é¨ç½²æºä¸åéè¦ nginxï¼ï¼å é¤ Redis ç¸å ³è¯´æï¼ä»£ç æªä½¿ç¨ï¼ï¼è¡¥ `sql_wyc.sql` ä¸ `summary.template-dir`ï¼è¡¥ `jwt.secret` åå¼è§åï¼è¡¥é¨ç½²åéªè¯æ¸ åã - 2026-08-27ï¼é¦çï¼zip é¨ç½²å + nginx æ¹æ¡ï¼ã package-deploy.py
New file @@ -0,0 +1,283 @@ # -*- coding: utf-8 -*- """TrafficAudit ä¸é®æå èæ¬ï¼å端æå»º -> å åµè¿å端 jar -> ç»è£ é¨ç½²å -> æ zip ç¨æ³ï¼python package-deploy.py [--no-build] """ import io, os, sys, shutil, zipfile, subprocess, datetime 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") 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" SKIP_DOC_DIRS = {"ai_demo", "usage_screenshots", "åè½æµè¯æ¥å", "工使¥ç»"} def rmtree_force(path): """å é¤ç®å½ï¼å æ¸ æåªè¯»å±æ§ï¼æºç®å½éåå¨åªè¯»æä»¶ï¼copy2 ä¼å¸¦è¿æ¥ï¼å¯¼è´ Windows ä¸ rmtree æ¥æç»è®¿é®ï¼""" if not os.path.isdir(path): return for r, d, fs in os.walk(path): for f in fs: try: os.chmod(os.path.join(r, f), 0o666) except OSError: pass shutil.rmtree(path, ignore_errors=True) def run(cmd, cwd, log): with io.open(log, "w", encoding="utf-8", newline="") as f: p = subprocess.run(cmd, cwd=cwd, stdout=f, stderr=subprocess.STDOUT, shell=True) return p.returncode def main(): do_build = "--no-build" not in sys.argv print("[1/6] å端æå»º ...") if do_build: rc = run('cmd /c "npm.cmd run build 1>build_prod.log 2>&1"', WEB, os.path.join(WEB, "build_prod.log")) print(" npm run build rc=%d" % rc) if rc != 0: raise SystemExit("å端æå»ºå¤±è´¥ï¼è§ traffic-audit-web/build_prod.log") dist = os.path.join(WEB, "dist") if not os.path.isfile(os.path.join(dist, "index.html")): raise SystemExit("æªæ¾å° dist/index.htmlï¼è¯·å æå»ºå端") print("[2/6] æ dist å åµè¿å端 static å¹¶æ jar ...") copied = [] try: rmtree_force(STATIC) shutil.copytree(dist, STATIC) for r, d, fs in os.walk(STATIC): for f in fs: copied.append(os.path.join(r, f)) rc = run('cmd /c "mvn.cmd -o -q clean package -DskipTests -f traffic-audit-server\\pom.xml"', ROOT, os.path.join(ROOT, "package_build.log")) if rc != 0: print(" 离线æå å¤±è´¥ï¼æ¹ä¸ºèç½æå ...") rc = run('cmd /c "mvn.cmd -q clean package -DskipTests -f traffic-audit-server\\pom.xml"', ROOT, os.path.join(ROOT, "package_build.log")) if rc != 0: raise SystemExit("å端æå 失败ï¼è§ package_build.log") finally: rmtree_force(STATIC) os.makedirs(STATIC, exist_ok=True) jar = os.path.join(SERVER, "target", JAR_NAME) if not os.path.isfile(jar): raise SystemExit("æªæ¾å° jar: " + jar) print(" jar=%.1f MB" % (os.path.getsize(jar) / 1048576.0)) print("[3/6] ç»è£ é¨ç½²ç®å½ %s ..." % STAGE) rmtree_force(STAGE) be = os.path.join(STAGE, "backend") fe = os.path.join(STAGE, "frontend") db = os.path.join(STAGE, "db") for d in (be, fe, db): os.makedirs(d) shutil.copy2(jar, os.path.join(be, JAR_NAME)) rmtree_force(os.path.join(be, "docs")) dst_docs = os.path.join(be, "docs") os.makedirs(dst_docs) for name in os.listdir(os.path.join(ROOT, "docs")): if name in SKIP_DOC_DIRS: continue src = os.path.join(ROOT, "docs", name) dst = os.path.join(dst_docs, name) if os.path.isdir(src): shutil.copytree(src, dst, ignore=shutil.ignore_patterns("è¾åº")) else: shutil.copy2(src, dst) shutil.copytree(dist, os.path.join(fe, "dist")) for s in ("init.sql", "sql_city_bus.sql", "sql_city_taxi.sql", "sql_wyc.sql"): shutil.copy2(os.path.join(ROOT, "docs", s), os.path.join(db, s)) print("[4/6] åå ¥é ç½®ä¸å¯å¨èæ¬ ...") io.open(os.path.join(be, "application.yml"), "w", encoding="utf-8", newline="\r\n").write(APPLICATION_YML) 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) print("[5/6] æ zip ...") if os.path.isfile(ZIP): os.remove(ZIP) n = 0 with zipfile.ZipFile(ZIP, "w", zipfile.ZIP_DEFLATED, compresslevel=6) as z: for r, d, fs in os.walk(STAGE): for f in fs: full = os.path.join(r, f) z.write(full, os.path.relpath(full, STAGE)) n += 1 print("[6/6] 宿ï¼%s (%.1f MB, %d 个æä»¶)" % (ZIP, os.path.getsize(ZIP) / 1048576.0, n)) APPLICATION_YML = u"""# ============================================================ # TrafficAudit å端å¤é¨é ç½®ï¼ä¸ jar å级å³å¯çæï¼ä¼å 级é«äº jar å ç½®é ç½®ï¼ # é¨ç½²å°æ°æºå¨åï¼è¯·**è³å°**ä¿®æ¹ä¸é¢æ 注 TODO çä¸å¤æ°æ®åºé ç½®ï¼ # ============================================================ server: port: 8090 app: captcha: required: false # ç产ç¯å¢å¦éå¾å½¢éªè¯ç ï¼æ¹ä¸º true spring: datasource: url: jdbc:mysql://127.0.0.1:3306/traffic_audit?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true username: root # TODO æ¹æä½ ç MySQL è´¦å· password: è¯·æ¹æä½ çæ°æ®åºå¯ç # TODO æ¹æä½ ç MySQL å¯ç driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 100MB max-request-size: 100MB jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: Asia/Shanghai mybatis-plus: mapper-locations: classpath*:/mapper/**/*.xml type-aliases-package: com.trafficaudit configuration: map-underscore-to-camel-case: true global-config: db-config: id-type: auto logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0 jwt: # å¿ é¡»æ¯ãBase64 åæ³å符 + é¿åº¦æ¯ 4 çåæ°ãï¼ä¸é¢è¿ä¸² 32 ä½åå è¿å¶å¯ç´æ¥ç¨ï¼ # ç产ç¯å¢å»ºè®®æ¢æèªå·±çéæºä¸²ï¼å¡«ä¸ææä¸åæ³å符ä¼å¯¼è´ç»å½ 500ï¼ secret: 8f2c1d64a7b34e09c5d81f6a2b0e7c93 expiration: 86400000 docs: template-root: docs city-passenger: template-dir: docs/åå¸å®¢è¿ passenger: template-dir: docs/å ¬è·¯æ 客 freight: template-dir: docs/è´§è¿ energy: template-dir: docs/è½è investment: template-dir: docs/æèµ/æ¨¡æ¿ summary: template-dir: docs/çææ±æ»å¤§è¡¨ # æ±æ»å¤§è¡¨æ¯çä¸çå¼åç §ä»¶æå¨ç®å½ï¼å¿ éï¼ deepseek: api-key: "" # AI åæç¨ï¼ç空å AI åæä¸å¯ç¨ api-url: https://api.deepseek.com/v1/chat/completions model: deepseek-chat """ START_CMD = u"""@echo off chcp 65001 >nul cd /d %~dp0 where java >nul 2>nul if errorlevel 1 ( echo [ERROR] æªæ¾å° javaï¼è¯·å å®è£ JDK 8 å¹¶å å ¥ PATH pause exit /b 1 ) echo ============================================ echo TrafficAudit å¯å¨ä¸ï¼http://localhost:8090 echo å端已å åµï¼ç´æ¥è®¿é® 8090 å³å¯ï¼ä¸éè¦ nginxï¼ echo æ¥å¿æ¾ç¤ºå¨æ¬çªå£ï¼å ³éçªå£å³åæ¢æå¡ echo ============================================ java -jar traffic-audit-server-1.0.0-SNAPSHOT.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 """ NGINX = u"""# å端 nginx é 置示ä¾ï¼åªæå¨ä¸æ³ç¨ãjar å åµåç«¯ãæ¶æéè¦ï¼ server { listen 8080; server_name localhost; root /opt/traffic-audit/frontend/dist; # æ¹æå®é è·¯å¾ index index.html; location /api/ { proxy_pass http://127.0.0.1:8090; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_read_timeout 300s; } location / { try_files $uri $uri/ /index.html; } } """ README = u"""TrafficAudit 交éè´§è¿ç»è®¡å®¡æ ¸ç³»ç» ââ é¨ç½²å ï¼{stamp}ï¼ ======================================================== ãç®å½ç»æã backend/ traffic-audit-server-1.0.0-SNAPSHOT.jar å端ç¨åºï¼å«å ¨é¨ä¾èµï¼**å·²å åµå端**ï¼ docs/ æ¥è¡¨æ¨¡æ¿ä¸è¿è¡æ°æ®ç®å½ï¼å¿ éï¼å¿å ï¼ application.yml å¤é¨é ç½®ï¼æ¹è¿éå³å¯ï¼æ ééæ°æå ï¼ start-backend.cmd / start-backend.sh å¯å¨èæ¬ frontend/ dist/ å端æå»ºäº§ç©ï¼å¤ç¨ï¼æ³ç¨ nginx æç®¡æ¶ç¨ï¼ nginx.conf.example nginx é ç½®ç¤ºä¾ db/ init.sql 建åºå»ºè¡¨ + é¢ç½®è´¦å·ï¼å¿ é¡»æ§è¡ï¼ sql_city_bus.sql åå¸å®¢è¿-å ¬äº¤æåº¦è¡¨ï¼å¿ é¡»æ§è¡ï¼ sql_city_taxi.sql åå¸å®¢è¿-åºç§æåº¦è¡¨/åºç§ææè¡¨ï¼å¿ é¡»æ§è¡ï¼ sql_wyc.sql ç½çº¦è½¦å ¨çæ»é表/订ååå¸å·è¡¨ï¼å¿ é¡»æ§è¡ï¼ README-é¨ç½²è¯´æ.txt ãé¨ç½²æºç¯å¢è¦æ±ã JDK 8ï¼å¿ éï¼ MySQL 5.7 / 8.0ï¼å¿ éï¼ **ä¸éè¦ Redis**ï¼ä»£ç æªä½¿ç¨ï¼æ§ç说æéç Redis æ¯éçé ç½®ï¼å¯å¿½ç¥ï¼ **ä¸éè¦ nginx**ï¼å端已å åµè¿ jarï¼è®¿é® 8090 å³å¯ï¼nginx ä» ä¸ºå¤éæ¹æ¡ï¼ ãé¨ç½²æ¥éª¤ã 1. åå§åæ°æ®åºï¼4 ä¸ªèæ¬é½è¦æ§è¡ï¼é¡ºåºå¦ä¸ï¼ mysql --default-character-set=utf8mb4 -u root -p < db/init.sql mysql --default-character-set=utf8mb4 -u root -p traffic_audit < db/sql_city_bus.sql mysql --default-character-set=utf8mb4 -u root -p traffic_audit < db/sql_city_taxi.sql mysql --default-character-set=utf8mb4 -u root -p traffic_audit < db/sql_wyc.sql é¢ç½®è´¦å·ï¼admin / admin123ï¼é¦æ¬¡ç»å½å请æ¹å¯ç ï¼ 2. æ¹é ç½® backend/application.yml - spring.datasource.url / username / password ï¼æ¹æé¨ç½²æºç MySQLï¼é»è®¤ç«¯å£ 3306ï¼ - jwt.secret ï¼æ¹æä¸ä¸²éæºå符串ï¼**å¿ é¡»æ¯ Base64 åæ³å符ä¸é¿åº¦æ¯ 4 çåæ°**ï¼å¦ 32 ä½åå è¿å¶ï¼å¡«ä¸æä¼ç»å½å¤±è´¥ï¼ - deepseek.api-key ï¼éè¦ AI åææ¶å¡«ï¼ä¸éè¦å¯ç空 注ï¼application.yml ä¸ jar å级å³çæï¼ä¸ç¨éæ°æå ã 3. å¯å¨å端ï¼å¨ backend ç®å½ä¸ï¼ Windowsï¼åå» start-backend.cmd Linuxï¼ sh start-backend.sh æåæ å¿ï¼åºç° "Started TrafficAuditApplication" ä¸ "Tomcat started on port(s): 8090" 4. 访é®ç³»ç» æµè§å¨æå¼ http://<é¨ç½²æºIP>:8090 ï¼å端已å åµï¼é¡µé¢ä¸æ¥å£åæºï¼ è´¦å·ï¼admin / admin123 ãæ°æ®è¿ç§»ï¼å¯éï¼ã æ³ææ¬æºæ°æ®ä¸å¹¶æ¬å°æ°æºå¨ï¼ç¨ mysqldumpï¼æ¬æº MySQL è¥ä¸å¨ 3306ï¼æå®é ç«¯å£æ¹ï¼ï¼ mysqldump -h 127.0.0.1 -P 3306 -u root -p --databases traffic_audit > traffic_audit_full.sql å卿°æºå¨æ§è¡ï¼ mysql -u root -p < traffic_audit_full.sql 注æï¼å ¨é dump ä¼å¸¦ä¸æ¬æºçè´¦å·å¯ç ï¼è¦ç init.sql é¢ç½®ç admin è´¦å·ã ã常è§é®é¢ã 1. å¯å¨æ¥ãæªæ¾å°æ°æ®ç®å½ docsã/ å¯¼åºæ¥ãæªæ¾å°æ¨¡æ¿æä»¶ãï¼ å¿ é¡»å¨ backend ç®å½ä¸å¯å¨ï¼jar ä¸ docs å级ï¼ï¼ä¸è¦åªæ· jarã 2. æ¥è¡¨å¯¼åºæ¥ãæªæ¾å°æ±æ»è¡¨æ¯çãYYYYå¹´Mæéè·¯è¿è¾éæ±æ»è¡¨.xlsxããï¼ docs/çææ±æ»å¤§è¡¨ ä¸ç¼ºå°è¯¥æä»½æ¯çï¼ææºæºå¨ç该æä»¶æ·è¿å»ã 3. 8090 端å£è¢«å ç¨ï¼æ¹ application.yml ç server.port åéå¯ã 4. 页颿弿¯ç©ºç½ï¼ç¡®è®¤è®¿é®çæ¯ http://<IP>:8090 æ ¹è·¯å¾ï¼ä¸æµè§å¨å¼ºå¶å·æ°ï¼Ctrl+F5ï¼ã 5. ä¸ä¼ 大æä»¶å¤±è´¥ï¼å端éå¶ 100MBï¼å·²é ç½®ï¼å¦åé¢è¿æäº nginxï¼é忥æ¾å¤§ client_max_body_sizeã ã忢æå¡ã Windowsï¼å ³é start-backend.cmd çªå£ Linuxï¼ Ctrl+Cï¼æ kill å¯¹åº java è¿ç¨ï¼ps -ef | grep javaï¼ """ if __name__ == "__main__": main() traffic-audit-server/src/main/java/com/trafficaudit/security/utils/JwtUtils.java
@@ -3,9 +3,13 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.impl.TextCodec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -13,11 +17,27 @@ @Component public class JwtUtils { private static final Logger log = LoggerFactory.getLogger(JwtUtils.class); @Value("${jwt.secret}") private String secret; @Value("${jwt.expiration}") private Long expiration; /** * ç¾åå¯é¥åèï¼jjwt 0.9.x é»è®¤æ secret å½ Base64 è§£ç ï¼è¥é ç½®æä¸æçéæ³ Base64 ä¼å¨ç»å½æ¶æ * ArrayIndexOutOfBoundsExceptionï¼è¡¨ç°ä¸ºãç»å½æ¥å£ 500ããè¿éåå åºï¼è½æ Base64 è§£ç å°±ç¨è§£ç ç»æ * ï¼ä¸åå² token å ¼å®¹ï¼ï¼å¦åæ UTF-8 åèå¤çï¼å¹¶ææç¤ºæå°æ¥å¿éã */ private byte[] secretKeyBytes() { try { return TextCodec.BASE64.decode(secret); } catch (Exception e) { log.warn("jwt.secret 䏿¯åæ³ç Base64 å符串ï¼å·²æ UTF-8 åèä½ä¸ºç¾åå¯é¥ï¼å»ºè®®æ¹æ 32 ä½éæºåå è¿å¶ä¸²ã"); return secret.getBytes(StandardCharsets.UTF_8); } } public String generateToken(String username) { Map<String, Object> claims = new HashMap<>(); @@ -27,19 +47,19 @@ .setSubject(username) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + expiration)) .signWith(SignatureAlgorithm.HS256, secret) .signWith(SignatureAlgorithm.HS256, secretKeyBytes()) .compact(); } public String getUsernameFromToken(String token) { Claims claims = Jwts.parser().setSigningKey(secret) Claims claims = Jwts.parser().setSigningKey(secretKeyBytes()) .parseClaimsJws(token).getBody(); return claims.getSubject(); } public boolean validateToken(String token) { try { Jwts.parser().setSigningKey(secret).parseClaimsJws(token); Jwts.parser().setSigningKey(secretKeyBytes()).parseClaimsJws(token); return true; } catch (Exception e) { return false;