zhizhijie
2026-09-20 35d098a89613c96179391178b7f8143dec393ada
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<#
  一键停止前后端(与 start-dev.ps1 配套)
  用法:powershell -NoProfile -ExecutionPolicy Bypass -File stop-dev.ps1
 
  说明:
  - 只停本项目相关进程:cmd.exe /c mvn.cmd ... spring-boot:run、cmd.exe /c npm.cmd run serve,
    以及它们的子进程(java / node / vue-cli-service),按进程树 taskkill /T /F;
  - 兜底再按命令行特征精确匹配 java(TrafficAuditApplication) 与 node(vue-cli-service) 的孤儿进程;
  - 不碰其它 node/java 进程(例如 Codex 的 node_repl)与用户自己开的 cmd 窗口;
  - 结束后检查 8090/8080 是否已释放。
#>
$ErrorActionPreference = 'Continue'
 
function Test-PortListening($port) {
  try { return [bool](Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction Stop) }
  catch { return $false }
}
 
function Stop-Tree($label, $procId) {
  Write-Host ("{0}:停止进程树 PID={1}" -f $label, $procId)
  & taskkill.exe /T /F /PID $procId 2>&1 | ForEach-Object { if ($_ -and $_ -notmatch '^SUCCESS') { "    $_" } }
}
 
# ---------- 1) 按「启动用的 cmd 父进程」整树结束 ----------
$roots = @(
  @{ Label = '后端'; Pattern = 'spring-boot:run' },
  @{ Label = '前端'; Pattern = 'npm.cmd run serve' }
)
$found = $false
$cmdProcs = Get-CimInstance Win32_Process -Filter "Name='cmd.exe'" -ErrorAction SilentlyContinue
foreach ($r in $roots) {
  $hits = @($cmdProcs | Where-Object { $_.CommandLine -and $_.CommandLine -like ('*' + $r.Pattern + '*') })
  if ($hits.Count -eq 0) { Write-Host ("{0}:未发现启动进程(可能已停止)" -f $r.Label); continue }
  $found = $true
  foreach ($h in $hits) { Stop-Tree $r.Label $h.ProcessId }
}
 
# ---------- 2) 兜底:孤儿 java / node ----------
$orphans = @(
  @{ Label = '后端(java 兜底)'; Name = 'java.exe'; Pattern = 'TrafficAuditApplication' },
  @{ Label = '前端(node 兜底)'; Name = 'node.exe'; Pattern = 'vue-cli-service' },
  @{ Label = '前端(inner cmd 兜底)'; Name = 'cmd.exe'; Pattern = 'vue-cli-service serve' }
)
foreach ($o in $orphans) {
  $hits = @(Get-CimInstance Win32_Process -Filter ("Name='" + $o.Name + "'") -ErrorAction SilentlyContinue |
            Where-Object { $_.CommandLine -and $_.CommandLine -like ('*' + $o.Pattern + '*') })
  foreach ($h in $hits) { $found = $true; Stop-Tree $o.Label $h.ProcessId }
}
 
if (-not $found) { Write-Host '没有发现需要停止的前后端进程。' }
 
# ---------- 3) 校验端口 ----------
Start-Sleep -Seconds 4
foreach ($port in 8090, 8080) {
  if (Test-PortListening $port) { Write-Host ("端口 {0}:仍在监听(未完全停止,请重跑一次)" -f $port) }
  else { Write-Host ("端口 {0}:已释放" -f $port) }
}