application.yaml
13.1 KB
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
spring:
application:
name: parking-server
profiles:
active: local
# ========== 引入「存量业务参数」文件 ==========
# 老工程按模块各有一份 application*.properties,红线第 9 条禁止改、importer 也故意不搬;
# 但存量代码里有 37 个 `@Value("${...}")` 是业务参数(不是连接串),不补就启动失败。
# 这一批集中收在 legacy-params.properties(由 tools/p2_audit_placeholders.py 捞出并核对)。
# ⚠️ 优先级:application-{profile}.yaml(profile 专属)> 本文件 > 被 import 的文件,
# 所以按环境覆盖这些参数时,写进 application-{profile}.yaml 即可。
config:
import: classpath:legacy-params.properties
# ========== Boot 1.5 → 2.x 的默认值翻转(必配,不是可选优化)==========
# 老工程是 Spring Boot 1.5.2,那时 spring.main.allow-circular-references 默认 true;
# 2.6 起默认 false,启动即抛
# "The dependencies of some of the beans in the application context form a cycle"。
# 存量代码是 2000+ 个 ServiceImpl 之间靠字段 @Autowired 互引,环是网状的
# (实测:DealGeoInOutParkDataSchedule → GeoInOutParkReportInnerServiceImpl → BerthsDaoImpl
# ⇄ ParkFreeBerthBizServiceImpl),且老代码里没有一处用 @Lazy / setter 注入规避。
# 拆环 = 改动存量业务装配方式,触碰项目红线第 6 条「禁止擅自重构业务逻辑」,故显式放行。
main:
allow-circular-references: true
# ⚠️ 这里**故意不写** allow-bean-definition-overriding(2.1 起默认 false,保持即可):
# 它是「两个**不同类**撞同一个 bean 名」的唯一探针,本次重构正是靠启动报错逐个揪出
# 9 组真实冲突并补上显式 bean 名修掉的。为封闭 jar 里 ChargeConfig ↔ ChargeService
# 那一组开全局放水,等于把最该发现的错误静默掉;那组已改用「精确排除」处理,
# 见 ParkingServerApplication 类注释与 AGENTS.md 坑 13/14。
# 资源信息:文件上传大小限制
servlet:
multipart:
max-file-size: 20MB
max-request-size: 20MB
# ========== 邮件(存量 pay/park 的 MailService,发票/异常告警用)==========
# 老工程把 spring.mail.* 写在**各模块的 application.properties** 里
# (zteits-pay / zteits-park 各一份,7 个 profile 各一组,值逐字相同),
# 红线第 9 条禁止改那些文件、importer 也故意不搬 —— 单 Jar 只有一份配置,
# 所以在这里补。四个键缺一不可:
# host —— MailSenderAutoConfiguration 的 @ConditionalOnProperty(prefix="spring.mail", name="host");
# 缺 host 就没有 JavaMailSender Bean,而 MailService 是裸 @Autowired JavaMailSender,
# 启动即报 `No qualifying bean of type 'org.springframework.mail.javamail.JavaMailSender'`
# (实测装配链:mailService → field 'sender')。
# username —— 两个 MailService 都用 @Value("${spring.mail.username}") **且没有默认值**,
# 缺失是**占位符解析失败**,比缺 Bean 更早炸。
# password —— 只在真正发信时用(Boot 的 test-connection 默认 false,启动不会去连 SMTP);
# **真实密码不进仓库**(红线 11),生产用 SPRING_MAIL_PASSWORD 注入,
# 待轮换的旧密码见 docs/密钥轮换清单.md。
# 默认 host/port 取老工程原值(smtp.163.com:25,不是密钥);默认 username/password 留空,
# 于是「能启动、发不出信、发信时以 auth 失败**报错**(而不是静默)」—— 这是没有凭据时的预期状态。
mail:
host: ${SPRING_MAIL_HOST:smtp.163.com}
port: ${SPRING_MAIL_PORT:25}
username: ${SPRING_MAIL_USERNAME:}
password: ${SPRING_MAIL_PASSWORD:}
# Jackson 全局配置
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
mvc:
pathmatch:
matching-strategy: ANT_PATH_MATCHER
# 未匹配到 Controller 时抛 NoHandlerFoundException,由 GlobalExceptionHandler 统一转成
# CommonResult(404) 的 JSON 兜底(未迁移的模块就是这种「路由不存在」的状态)。
# 否则前端拿到的是 Spring Boot 默认 HTML 错误页,无法按 code 处理。
throw-exception-if-no-handler-found: true
web:
resources:
# 关闭默认静态资源映射,配合上面的开关;knife4j / springdoc 的 /doc.html、/v3/api-docs
# 由它们自己注册的 ResourceHandler 提供,与本开关无关(已实测仍可访问)。
add-mappings: false
# 定时任务(Quartz):P0 用内存存储,P1 起改为数据库存储
quartz:
job-store-type: memory
properties:
org:
quartz:
scheduler:
instance-id: AUTO
instance-name: parkingScheduler
threadPool:
threadCount: 20
# 消息队列(Redis 实现)默认关闭外部 MQ
rabbitmq:
listener:
simple:
auto-startup: false
server:
port: 48080
servlet:
encoding:
charset: UTF-8
force: true
# ========== 项目业务配置 ==========
parking:
info:
version: 1.0.0
base-package: com.zteits.parking
# 注:P0 的骨架占位开关 `parking.p0.enabled` 已随 P0StubConfiguration 一起删除。
# P1 起 OAuth2TokenCommonApi / PermissionCommonApi / DictDataCommonApi 三个跨模块契约
# 均由 parking-module-system 的 OAuth2TokenServiceImpl / PermissionServiceImpl /
# DictDataServiceImpl 提供(三者分别继承了对应契约接口)。
web:
admin-api:
prefix: /admin-api
controller: '**.controller.admin.**'
app-api:
prefix: /app-api
controller: '**.controller.app.**'
admin-ui:
url: http://localhost:5173
security:
token-header: Authorization
token-parameter: token
mock-enable: false
mock-secret: test
password-encoder-length: 4
permit-all-urls:
- /actuator/**
- /doc.html
- /swagger-ui/**
- /swagger-ui.html
- /v3/api-docs/**
- /webjars/**
- /favicon.ico
swagger:
title: ZTEITS 智能停车云平台
description: 停车云平台管理后台接口文档(模块化单体,单 Jar 发布)
author: ZIEITS
version: 1.0.0
url: https://www.zteits.com
email: dev@zteits.com
license: MIT
license-url: https://opensource.org/licenses/MIT
cache:
redis-scan-batch-size: 30
# ========== 刷新缓存共享密钥(老门户 RefreshCacheController 4 条 @NoAuth)==========
# 老代码写死 32 位共享密钥,迁移时按 AGENTS.md「批 6 第三十四切片」④ (B) 改配置化(红线 11)。
# 代码里**零密钥、无默认值**;这里默认取环境变量、缺省为空 ⇒ 任何环境不配即 fail-closed
# (一律回 "token不正确")。本地测试值在 application-local.yaml 覆盖;生产用
# PARKING_REFRESH_CACHE_TOKEN 或 --parking.refresh-cache.token=... 配成现网原串。
refresh-cache:
token: ${REFRESH_CACHE_TOKEN:}
# ========== 老新组织 id 换算表(P3 组织口径桥,批 6 第四十七切片)==========
# 新 `system_org.id` 与存量业务表里存的 `sys_org.id` 是两个空间(坑 22)。
# `LoginUserBridge` 用它把登录人的 orgId 换算成老 id 再交给存量服务;格式 `新id:老id,...`。
# **默认空 ⇒ 恒等映射**,任何环境不配都与改造前完全一致(配置在 profile/环境变量里给)。
# ========== 老新操作员 id 换算表(P3 ②,第一百六十三切片)==========
# 新 `system_users.id` 与存量审计列(create_op/modify_op/create_empid/s_op_id)里的
# `sys_op.id` 是两个空间。`LoginUserBridge` 用它把 opId 换算成老操作员 id;
# 格式 `新id:老id,...`。**默认空 ⇒ 恒等映射**,任何环境不配都与改造前完全一致。
legacy:
org-id-mapping: ${LEGACY_ORG_ID_MAPPING:}
op-id-mapping: ${LEGACY_OP_ID_MAPPING:}
# ========== 企业微信(存量 zteits-wxcp-portal 的告警发送)==========
# 随迁进 parking-module-system 的 com.zteits.wxcp.* 用 @ConfigurationProperties(wechat.cp) 绑定。
# ⚠️ 这两个键**必须存在**:WxCpConfiguration.initServices() 是 @PostConstruct,
# 里面直接 properties.getAppConfigs().stream() —— appConfigs 为 null 会启动即 NPE。
# 这里给**空列表**是刻意的:空列表能正常绑定(不执行任何 lambda),
# 于是没有企业微信凭据的环境也能启动,只是真的要走告警时
# WxCpConfiguration.getCpService(agentId) 返回 null(外部集成未配置)。
# 生产/测试环境在此之上覆盖(凭据本身见 docs/密钥轮换清单.md,不进仓库):
# wechat:
# cp:
# corp-id: ww...
# app-configs:
# - agent-id: 1000002
# secret: ${WECHAT_CP_SECRET_1000002:}
# token: ${WECHAT_CP_TOKEN_1000002:}
# aes-key: ${WECHAT_CP_AESKEY_1000002:}
wechat:
cp:
corp-id: ${WECHAT_CP_CORP_ID:}
app-configs: []
# ========== SpringDoc / Knife4j 接口文档 ==========
springdoc:
api-docs:
enabled: true
path: /v3/api-docs
swagger-ui:
path: /swagger-ui
knife4j:
enable: true
setting:
language: zh_cn
# ========== MyBatis-Plus 配置 ==========
# 核心:存量 mapper XML 与新建的 MyBatis-Plus 共用同一个 SqlSessionFactory,
# mapper-locations 一条通配同时命中「新代码 Mapper XML」与「存量 mybatis/mapper|smapper」。
mybatis-plus:
mapper-locations:
- classpath*:mapper/**/*.xml
- classpath*:mybatis/mapper/**/*.xml
- classpath*:mybatis/smapper/**/*.xml
type-aliases-package: com.zteits.parking.module.*.dal.dataobject,com.zteits.parking.module.*.domain
global-config:
banner: false
db-config:
id-type: AUTO
# ⚠️ 存量六个库**没有 del_flag 列**(已核验:0 处),因此这里不配置全局逻辑删除。
# 详见 parking-spring-boot-starter-mybatis 的 BaseDO 类注释。
table-underline: true
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
call-setters-on-nulls: true
jdbc-type-for-null: 'null'
# ↓↓↓ 以下 3 项是**照搬老工程** mybatis-plugin.xml 的 settings
# (zteits-{park,pay,bill}/src/main/resources/mybatis/mybatis-plugin.xml,三份逐字相同)。
# 老工程走的是自己 new SqlSessionFactoryBean 的路线,这些 settings 写在 XML 里;
# 新工程的 SqlSessionFactory 由 MyBatis-Plus 建,所以要把**非默认值**的挑出来补在这里。
# 逐项对照过 10 条 setting,只有下面 3 条与 MyBatis 默认值不同:
# mapUnderscoreToCamelCase=true —— 已在上方
# cacheEnabled=false —— 已在上方
# localCacheScope=STATEMENT —— MyBatis 默认 SESSION,**必须补**
# useGeneratedKeys=true —— MyBatis 默认 **false**,**必须补**
# defaultStatementTimeout=60 —— 默认 null(不超时),**必须补**
# lazyLoadingEnabled / multipleResultSetsEnabled / useColumnLabel /
# autoMappingBehavior / defaultExecutorType —— 与默认值一致,不必写
local-cache-scope: statement
default-statement-timeout: 60
use-generated-keys: true
# ========== PageHelper(仅存量代码搬迁时按需使用,新代码禁止)==========
pagehelper:
helper-dialect: mysql
reasonable: true
support-methods-arguments: true
# ⚠️ `page-size-zero: true` 是**必须**的,不是可选项:它决定 `startPage(n, 0)` 是
# 「查全部」还是「查空」,而存量代码里 60+ 个导出端点全都靠 `new BaseInfo(1, 0)`
# 表达「不分页、导全部」。
#
# 老栈 PageHelper 5.0.0:`startPage(1, 0)` → LIMIT **不拼** → 全量返回(total=1, list.size=1)
# 新栈 PageHelper 6.1.1(`page-size-zero` 默认 false):拼 `LIMIT 0` → **0 行**(total=1, list.size=0)
# 实测证据与复现脚本见 AGENTS.md「pageSize=0:老栈查全部、新栈查空」一节
# (/tmp/pgprobe 的两版本对照实验)。不设这一项,所有导出都会**静默导出空表**。
#
# 老工程 application.properties 里没写这一项 —— 那不是"老栈也不需要",而是 5.0.0 里
# pageSize=0 本来就不拼 LIMIT,`pageSizeZero` 只管 RowBounds 那条路径。换了 PageHelper
# 大版本后语义变了,必须在**新栈**显式补回来。
page-size-zero: true
# 老工程 application.properties 里还有 `pagehelper.dialect=com.github.pagehelper.PageHelper`
# 与 `pagehelper.params=countSql`:前者是 5.x 的自定义 dialect 类全名(6.x 已废弃该配置形态),
# 后者是 supportMethodsArguments 的默认值,二者都无迁移必要,故不搬。
# ========== Actuator 健康检查 ==========
management:
endpoints:
web:
base-path: /actuator
exposure:
include: '*'
endpoint:
health:
show-details: always
# ========== 日志 ==========
logging:
file:
name: ./logs/${spring.application.name}/${spring.application.name}.log