liujie
5 天以前 08c181231519361f1b7a533d1c7d8b00b776e787
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
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Java 服务端开发标准</title>
<style>
  :root{
    --c-bg:#ffffff;
    --c-text:#1f2329;
    --c-muted:#646a73;
    --c-border:#dee0e3;
    --c-primary:#2456e6;
    --c-accent:#00a874;
    --c-warn:#e6760c;
    --c-danger:#e02d2d;
    --c-code-bg:#f5f6f7;
    --c-table-head:#f0f2f5;
    --c-block:#f8f9fb;
  }
  *{box-sizing:border-box;}
  body{
    margin:0;
    background:var(--c-bg);
    color:var(--c-text);
    font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;
    font-size:15px;
    line-height:1.75;
    padding:32px 48px 80px;
    max-width:1100px;
    margin:0 auto;
  }
  h1{font-size:28px;margin:0 0 6px;padding-bottom:14px;border-bottom:3px solid var(--c-primary);}
  h2{font-size:20px;margin:44px 0 14px;padding-left:12px;border-left:4px solid var(--c-primary);}
  h3{font-size:16px;margin:24px 0 10px;color:#2b2f36;}
  p{margin:8px 0;}
  .meta{color:var(--c-muted);font-size:13px;margin:0 0 20px;}
  table{border-collapse:collapse;width:100%;margin:14px 0;font-size:14px;}
  th,td{border:1px solid var(--c-border);padding:8px 12px;text-align:left;vertical-align:top;}
  th{background:var(--c-table-head);font-weight:600;}
  tr:nth-child(even) td{background:#fbfcfd;}
  code{background:var(--c-code-bg);padding:2px 6px;border-radius:4px;font-family:"JetBrains Mono",Consolas,monospace;font-size:13px;color:#c41d7f;}
  pre{background:var(--c-block);border:1px solid var(--c-border);border-radius:8px;padding:14px 16px;overflow-x:auto;margin:14px 0;}
  pre code{background:none;padding:0;color:var(--c-text);font-size:13px;}
  ul,ol{margin:8px 0;padding-left:24px;}
  li{margin:4px 0;}
  .tag{display:inline-block;padding:1px 9px;border-radius:4px;font-size:12px;font-weight:600;margin-right:6px;vertical-align:middle;}
  .tag-must{background:#fde2e2;color:var(--c-danger);}
  .tag-should{background:#fff0db;color:var(--c-warn);}
  .note{background:var(--c-block);border-left:4px solid var(--c-accent);padding:10px 16px;margin:14px 0;border-radius:0 6px 6px 0;}
  .warn{background:#fff8ef;border-left:4px solid var(--c-warn);padding:10px 16px;margin:14px 0;border-radius:0 6px 6px 0;}
  .bad{color:var(--c-danger);}
  .good{color:var(--c-accent);}
  .toc{background:var(--c-block);border:1px solid var(--c-border);border-radius:8px;padding:14px 22px;margin:18px 0;}
  .toc ol{columns:2;column-gap:40px;}
  .toc li{break-inside:avoid;}
  .part-title{margin:52px 0 6px;font-size:17px;font-weight:700;color:#2456e6;letter-spacing:1px;border-bottom:1px dashed #dee0e3;padding-bottom:6px;}
  .toc ol.single{columns:1;}
  .toc .grp{margin:10px 0 2px;}
  .footer{margin-top:60px;padding-top:16px;border-top:1px solid var(--c-border);color:var(--c-muted);font-size:13px;}
  .cm{color:#8a8f99;}
</style>
</head>
<body>
 
<h1>Java 服务端开发标准</h1>
<p class="meta">适用技术栈:Java 8+ / Spring Boot / MyBatis &nbsp;|&nbsp; 版本:v1.5 &nbsp;|&nbsp; 生效日期:2026-08-24</p>
 
<div class="note"><b>说明:</b>本标准为团队 Java 服务端开发的强制基线,按工程结构、编码、数据库、接口与可观测、稳定性与性能、安全、测试、版本管理与 AI 协作、部署九大类组织,共 23 条核心规则。所有提交代码(含外协)必须遵守;违反规则项在 Code Review 中一律打回。</div>
 
<div class="toc">
<h3>目录(按归类分为八部分,共 22 条规则)</h3>
<p class="grp"><b>第一部分 · 工程结构规范</b></p>
<ol class="single"><li>工程结构规范(MVC 分层)</li></ol>
<p class="grp"><b>第二部分 · 编码规范</b></p>
<ol class="single" start="2">
<li>类名命名规范(驼峰写法)</li>
<li>方法名规范(见名知意)</li>
<li>实体类命名规范</li>
<li>实体类注释规范</li>
<li>方法注释与业务流程注释规范</li>
<li>方法体行数与公共方法抽离</li>
<li>禁止魔法值,统一使用枚举</li>
</ol>
<p class="grp"><b>第三部分 · 数据库规范</b></p>
<ol class="single" start="9">
<li>数据库设计规范</li>
<li>SQL 与查询禁项规范</li>
</ol>
<p class="grp"><b>第四部分 · 接口与可观测规范</b></p>
<ol class="single" start="11">
<li>接口统一返回体规范</li>
<li>全局异常处理规范</li>
<li>日志规范</li>
</ol>
<p class="grp"><b>第五部分 · 稳定性与性能规范</b></p>
<ol class="single" start="14">
<li>线程池规范</li>
<li>幂等规范</li>
</ol>
<p class="grp"><b>第六部分 · 安全规范</b></p>
<ol class="single" start="16">
<li>鉴权与越权防护规范</li>
<li>防注入规范</li>
</ol>
<p class="grp"><b>第七部分 · 测试规范</b></p>
<ol class="single" start="18">
<li>单元测试规范</li>
</ol>
<p class="grp"><b>第八部分 · 版本管理与 AI 协作规范</b></p>
<ol class="single" start="19">
<li>Git 提交与配套产物同步规范</li>
<li>AI 协作:新功能开发文档先行</li>
<li>AI 协作:功能修改文档先改</li>
<li>AI 协作:开发文档同步提交 Git</li>
</ol>
<p class="grp"><b>第九部分 · 部署规范</b></p>
<ol class="single" start="23">
<li>部署文档规范</li>
</ol>
</div>
 
<div class="part-title">第一部分 · 工程结构规范</div>
<!-- 1 -->
<h2>一、工程结构规范(MVC 分层)</h2>
 
<h3>1.1 标准工程结构</h3>
<p>统一采用 MVC 三层结构:<b>接口写在 Controller,业务逻辑写在 Service,数据库查询写在 Mapper</b>。</p>
 
<pre><code>project-name/
└── src/main/java/com/company/project/
    ├── controller/            <span class="cm"># 接口层:参数接收与校验、调用 Service、返回结果</span>
    │   ├── OrderController.java
    │   └── UserController.java
    ├── service/               <span class="cm"># 业务层:接口定义 + 实现,承载全部业务逻辑</span>
    │   ├── OrderService.java        <span class="cm"># 订单业务接口类</span>
    │   ├── UserService.java         <span class="cm"># 用户业务接口类</span>
    │   └── impl/
    │       ├── OrderServiceImpl.java
    │       └── UserServiceImpl.java
    ├── mapper/                <span class="cm"># 数据层:数据库查询,不含业务逻辑</span>
    │   ├── OrderMapper.java
    │   └── UserMapper.java
    ├── model/
    │   ├── entity/            <span class="cm"># 实体类</span>
    │   ├── dto/               <span class="cm"># 入参对象</span>
    │   └── vo/                <span class="cm"># 返回对象</span>
    ├── enums/                 <span class="cm"># 枚举类</span>
    ├── config/                <span class="cm"># 配置类</span>
    ├── common/                <span class="cm"># 常量、统一返回体、全局异常处理</span>
    └── Application.java</code></pre>
 
<h3>1.2 各层职责边界</h3>
<table>
<tr><th style="width:110px">层</th><th>只做</th><th>禁止</th></tr>
<tr><td>Controller</td><td>接收/校验参数、调用 Service、组装返回结果</td><td>写 if-else 业务逻辑、直接调 Mapper、直接操作数据库</td></tr>
<tr><td>Service</td><td>全部业务逻辑、事务控制、多表编排、规则校验</td><td>处理 HTTP 协议细节(request/response 对象)</td></tr>
<tr><td>Mapper</td><td>单表/关联 SQL 查询与写入</td><td>写业务判断逻辑、循环调用数据库</td></tr>
</table>
 
<h3>1.3 订单模块示例(接口类 + 实现 + 数据层)</h3>
 
<pre><code><span class="cm">// ── Controller:只做参数接收与调用 ──</span>
@RestController
@RequestMapping("/api/v1/order")
public class OrderController {
 
    @Resource
    private OrderService orderService;
 
    /**
     * 创建订单接口
     */
    @PostMapping("/create")
    public Result&lt;OrderDetailVO&gt; createOrder(@RequestBody @Valid OrderCreateDTO dto) {
        return Result.success(orderService.createOrder(dto));
    }
}
 
<span class="cm">// ── Service 接口类:订单业务契约 ──</span>
public interface OrderService {
 
    /**
     * 创建订单
     */
    OrderDetailVO createOrder(OrderCreateDTO dto);
 
    /**
     * 根据订单号查询订单详情
     */
    OrderDetailVO getOrderDetailByOrderNo(String orderNo);
}
 
<span class="cm">// ── ServiceImpl:业务逻辑全部在此 ──</span>
@Service
public class OrderServiceImpl implements OrderService { ... }
 
<span class="cm">// ── Mapper:只写数据库查询 ──</span>
@Mapper
public interface OrderMapper {
 
    /**
     * 新增订单
     */
    int insert(OrderInfo order);
 
    /**
     * 根据订单号查询订单
     */
    OrderInfo selectByOrderNo(@Param("orderNo") String orderNo);
}</code></pre>
 
 
<div class="part-title">第二部分 · 编码规范</div>
<!-- 2 -->
<h2>二、类名命名规范(驼峰写法)</h2>
 
<table>
<tr><th style="width:150px">规则项</th><th>要求</th></tr>
<tr><td>写法</td><td>UpperCamelCase(大驼峰):每个单词首字母大写,其余小写</td></tr>
<tr><td>构成</td><td>名词或名词短语,体现类的职责</td></tr>
<tr><td>禁止</td><td>下划线(<code>User_Order</code>)、全小写(<code>userorder</code>)、拼音(<code>ZhangHu</code>)、数字结尾(<code>Util2</code>)</td></tr>
</table>
 
<h3>2.1 各类对象命名模板</h3>
<table>
<tr><th style="width:170px">类型</th><th>后缀约定</th><th>正确示例</th><th>错误示例</th></tr>
<tr><td>控制器</td><td>Controller</td><td><code>OrderController</code></td><td><code>OrderApi</code>、<code>orderController</code></td></tr>
<tr><td>业务接口</td><td>Service</td><td><code>OrderService</code></td><td><code>IOrderService</code></td></tr>
<tr><td>业务实现</td><td>ServiceImpl</td><td><code>OrderServiceImpl</code></td><td><code>OrderServiceImple</code></td></tr>
<tr><td>数据访问</td><td>Mapper</td><td><code>OrderMapper</code></td><td><code>OrderDao</code>、<code>OrderDB</code></td></tr>
<tr><td>实体类</td><td>领域名词</td><td><code>OrderInfo</code>、<code>UserInfo</code></td><td><code>OrderEntityPO</code></td></tr>
<tr><td>枚举类</td><td>Enum 结尾</td><td><code>OrderStatusEnum</code></td><td><code>OrderStatus</code>(与实体混淆)</td></tr>
<tr><td>工具类</td><td>Util 结尾</td><td><code>DateUtil</code></td><td><code>Tools</code>、<code>Helper</code></td></tr>
<tr><td>异常类</td><td>Exception 结尾</td><td><code>BusinessException</code></td><td><code>MyError</code></td></tr>
<tr><td>常量类</td><td>Constant 结尾</td><td><code>OrderConstant</code></td><td><code>Const</code></td></tr>
</table>
 
<h3>2.2 示例</h3>
<pre><code><span class="cm">// 正确:大驼峰,职责清晰</span>
public class OrderPayService { }
 
<span class="cm">// 错误:下划线、拼音、全小写</span>
public class Order_Pay_Service { }
public class DingDanFuWu { }</code></pre>
 
<!-- 3 -->
<h2>三、方法名规范(见名知意)</h2>
 
<p>方法名使用小驼峰(lowerCamelCase),<b>必须能表达方法意图</b>——看方法名即可知道它做什么,不需要读实现。</p>
 
<h3>3.1 命名公式</h3>
<table>
<tr><th style="width:130px">操作类型</th><th>命名公式</th><th>示例</th></tr>
<tr><td>查询</td><td>get / find / query + 对象 + 条件</td><td><code>getOrderById</code>、<code>findPaidOrdersByUserId</code></td></tr>
<tr><td>新增</td><td>save / add / create + 对象</td><td><code>saveOrder</code>、<code>createPaymentRecord</code></td></tr>
<tr><td>修改</td><td>update + 对象 + 变更点</td><td><code>updateOrderStatus</code>、<code>updateUserPhone</code></td></tr>
<tr><td>删除</td><td>delete / remove + 对象</td><td><code>deleteOrderById</code></td></tr>
<tr><td>校验</td><td>check / validate + 校验点</td><td><code>checkOrderPayable</code>、<code>validatePhone</code></td></tr>
<tr><td>判断</td><td>is / has / exists + 条件</td><td><code>isVipUser</code>、<code>hasUnpaidOrder</code></td></tr>
<tr><td>转换</td><td>对象A + to + 对象B</td><td><code>orderToDTO</code>、<code>dtoToEntity</code></td></tr>
<tr><td>统计</td><td>count / sum + 维度</td><td><code>countTodayOrders</code></td></tr>
</table>
 
<h3>3.2 正反示例</h3>
<pre><code><span class="cm">// 错误:看不出意图,需要读实现才知道干什么</span>
public void handle(Order order) { }
public List&lt;Order&gt; query1(Long userId) { }
public boolean doCheck(Object o) { }
 
<span class="cm">// 正确:方法名即文档</span>
public void payOrder(Order order) { }
public List&lt;Order&gt; queryUnpaidOrdersByUserId(Long userId) { }
public boolean checkOrderWithinPayDeadline(Order order) { }</code></pre>
 
<div class="warn"><b>Review 检查点:</b>方法名中出现 <code>handle / process / do / execute / a1 / query1</code> 等无意图词时,要求重命名后再合入。</div>
 
<!-- 4 -->
<h2>四、实体类命名规范</h2>
 
<ul>
<li>实体类名使用<b>大驼峰</b>,与数据库表名对应:表 <code>order_info</code> → 实体 <code>OrderInfo</code>。</li>
<li>实体类字段与表字段对应,Java 侧小驼峰:<code>order_no</code> → <code>orderNo</code>。</li>
<li>禁止在实体类上使用 <code>@Data</code> 同时可变共享(多线程场景);推荐 <code>@Getter/@Setter</code> 显式控制。</li>
<li>DTO(入参)、VO(出参)与 Entity 分离,禁止一个类既当实体又当接口对象。</li>
</ul>
 
<table>
<tr><th style="width:150px">数据库表</th><th>实体类(Entity)</th><th>传输对象(DTO)</th><th>返回对象(VO)</th></tr>
<tr><td><code>order_info</code></td><td><code>OrderInfo</code></td><td><code>OrderCreateDTO</code></td><td><code>OrderDetailVO</code></td></tr>
<tr><td><code>user_info</code></td><td><code>UserInfo</code></td><td><code>UserRegisterDTO</code></td><td><code>UserBaseVO</code></td></tr>
</table>
 
<!-- 5 -->
<h2>五、实体类注释规范</h2>
 
<p><span class="tag tag-must">必须</span>每个实体类具备<b>完整注释</b>:类注释 + 全部字段注释,字段注释与数据库字段 COMMENT 保持一致。</p>
 
<h3>5.1 注释模板</h3>
<pre><code>/**
 * 订单信息实体
 * 对应表:order_info
 *
 * @author zhangsan
 * @date 2026-08-24
 */
@Data
@TableName("order_info")
public class OrderInfo {
 
    /** 主键ID(雪花算法生成) */
    private Long id;
 
    /** 订单编号(业务唯一) */
    private String orderNo;
 
    /** 用户ID(关联 user_info.id) */
    private Long userId;
 
    /** 订单金额(单位:分) */
    private Long orderAmount;
 
    /** 订单状态 0-待支付 1-已支付 2-已取消 3-已完成(见 OrderStatusEnum) */
    private Integer orderStatus;
 
    /** 创建时间 */
    private Date createTime;
 
    /** 更新时间 */
    private Date updateTime;
 
    /** 逻辑删除标识 0-正常 1-已删除 */
    private Integer isDeleted;
}</code></pre>
 
<h3>5.2 字段注释要求</h3>
<table>
<tr><th style="width:220px">字段类型</th><th>注释必须说明</th></tr>
<tr><td>状态/类型字段</td><td>枚举全部取值含义,并标注对应枚举类</td></tr>
<tr><td>金额字段</td><td>单位(分/元),避免歧义</td></tr>
<tr><td>外键关联字段</td><td>关联的表与字段</td></tr>
<tr><td>时间字段</td><td>业务含义(创建/支付/完成时间)</td></tr>
<tr><td>布尔/标识字段</td><td>每个取值的含义</td></tr>
</table>
 
<!-- 6 -->
<h2>六、方法注释与业务流程注释规范</h2>
 
<h3>6.1 通用方法注释模板</h3>
<p><span class="tag tag-must">必须</span>所有方法具备 Javadoc 注释:说明用途、参数、返回值、异常。</p>
 
<pre><code>/**
 * 根据用户ID查询未支付订单列表
 *
 * @param userId   用户ID,不可为空
 * @param pageNum  页码,从 1 开始
 * @param pageSize 每页条数,最大 100
 * @return 未支付订单分页结果,无数据时返回空分页对象
 * @throws BusinessException 用户不存在时抛出(错误码 20001)
 */
public Page&lt;OrderInfo&gt; queryUnpaidOrdersByUserId(Long userId, int pageNum, int pageSize) { }</code></pre>
 
<h3>6.2 核心业务功能:完整业务流程注释</h3>
<p><span class="tag tag-must">必须</span>核心业务方法(订单创建、支付回调、状态流转等)在方法内部按<b>步骤编号</b>写清业务流程,步骤注释使用 <code>STEP x:</code> 格式:</p>
 
<pre><code>/**
 * 创建订单(核心业务)
 * 业务流程:参数校验 → 商品与价格校验 → 幂等校验 → 生成订单 → 扣减库存 → 发送延迟取消消息
 */
@Transactional(rollbackFor = Exception.class)
public OrderInfo createOrder(OrderCreateDTO dto) {
 
    // STEP 1: 参数基础校验(商品、数量、地址非空)
    checkCreateOrderParams(dto);
 
    // STEP 2: 查询商品信息并校验上架状态、价格以服务端为准(防止前端篡改价格)
    ProductInfo product = productMapper.selectById(dto.getProductId());
    checkProductSellable(product);
 
    // STEP 3: 幂等校验,同一幂等键的重复请求直接返回已存在订单
    OrderInfo existOrder = queryOrderByIdempotentKey(dto.getIdempotentKey());
    if (existOrder != null) {
        return existOrder;
    }
 
    // STEP 4: 生成订单编号并落库(金额单位为分,取服务端价格计算)
    OrderInfo order = buildOrder(dto, product);
    orderMapper.insert(order);
 
    // STEP 5: 扣减库存(库存不足抛业务异常,事务回滚订单)
    productMapper.deductStock(product.getId(), dto.getProductCount());
 
    // STEP 6: 发送延迟消息,超时未支付自动取消订单(消息发送失败仅告警,不回滚)
    sendDelayCancelMessage(order);
 
    return order;
}</code></pre>
 
<h3>6.3 注释等级要求</h3>
<table>
<tr><th style="width:180px">方法类型</th><th>注释要求</th></tr>
<tr><td>Controller 层接口</td><td>Javadoc:接口用途 + 参数 + 返回 + 示例说明</td></tr>
<tr><td>Service 公共方法</td><td>Javadoc 完整四要素(用途/参数/返回/异常)</td></tr>
<tr><td>核心业务方法</td><td>Javadoc + 方法体内 STEP 分步流程注释</td></tr>
<tr><td>私有工具方法</td><td>至少一行说明用途;复杂算法需说明思路</td></tr>
<tr><td>Getter/Setter</td><td>Lombok 生成,无需注释</td></tr>
</table>
 
<!-- 7 -->
<h2>七、方法体行数与公共方法抽离</h2>
 
<table>
<tr><th style="width:240px">规则</th><th>要求</th></tr>
<tr><td>单个方法体行数上限</td><td><b>不能超过 300 行</b>;超过即视为设计缺陷,必须拆分</td></tr>
<tr><td>重复代码</td><td>相同/相似的代码块出现 <b>2 次以上</b>,必须抽离成公共方法</td></tr>
<tr><td>公共方法归属</td><td>仅本类用 → 私有方法;跨类复用 → 工具类(Util)或公共 Service</td></tr>
<tr><td>建议目标</td><td>普通方法控制在 80 行内;超 300 行为硬性红线</td></tr>
</table>
 
<h3>7.1 拆分方法示例</h3>
<pre><code><span class="cm">// 错误:一个方法 400+ 行,参数校验、金额计算、落库、通知全部堆在一起</span>
public void createOrder(OrderCreateDTO dto) {
    <span class="cm">// ...300 行混合逻辑...</span>
}
 
<span class="cm">// 正确:按业务步骤抽成私有方法,主方法只保留流程骨架</span>
public void createOrder(OrderCreateDTO dto) {
    checkCreateOrderParams(dto);          <span class="cm">// 抽离:参数校验</span>
    OrderInfo order = buildOrder(dto);    <span class="cm">// 抽离:组装订单(金额计算复用 calcOrderAmount)</span>
    saveOrder(order);                     <span class="cm">// 抽离:订单落库</span>
    notifyUserOrderCreated(order);        <span class="cm">// 抽离:用户通知</span>
}
 
<span class="cm">// 抽离出的公共方法:多处复用的金额计算</span>
private Long calcOrderAmount(Long unitPrice, Integer count, Long discountAmount) {
    return unitPrice * count - discountAmount;
}</code></pre>
 
<h3>7.2 抽离判断流程</h3>
<ol>
<li>出现第二次复制粘贴 → 立即抽公共方法(禁止“先复制,后面再改”);</li>
<li>方法超 300 行 → 按业务步骤拆分为多个私有方法,主方法只保留流程编排;</li>
<li>私有方法被第二个类需要 → 上移到工具类或公共 Service;</li>
<li>抽离的方法遵循第三条规范:方法名表达意图。</li>
</ol>
 
<!-- 8 -->
<h2>八、禁止魔法值,统一使用枚举</h2>
 
<p><b>魔法值(Magic Value)</b>指代码中直接硬编码的数字或字符串常量。<span class="tag tag-must">必须</span>用枚举类或常量类替代。</p>
 
<h3>8.1 正反示例</h3>
<pre><code><span class="cm">// 错误:魔法值,1、2、"PAID" 散落各处,含义不明、改不动</span>
if (order.getStatus() == 2) { ... }
if ("PAID".equals(payResult)) { ... }
 
<span class="cm">// 正确:枚举统一收口</span>
if (OrderStatusEnum.PAID.getCode().equals(order.getOrderStatus())) { ... }
if (PayResultEnum.PAID.getCode().equals(payResult)) { ... }</code></pre>
 
<h3>8.2 标准枚举模板</h3>
<pre><code>/**
 * 订单状态枚举
 *
 * @author zhangsan
 * @date 2026-08-24
 */
@Getter
@AllArgsConstructor
public enum OrderStatusEnum {
 
    /** 待支付 */
    UNPAID(0, "待支付"),
 
    /** 已支付 */
    PAID(1, "已支付"),
 
    /** 已取消 */
    CANCELED(2, "已取消"),
 
    /** 已完成 */
    FINISHED(3, "已完成");
 
    /** 状态码(对应 order_info.order_status) */
    private final Integer code;
 
    /** 状态描述 */
    private final String desc;
 
    /**
     * 根据 code 获取枚举
     */
    public static OrderStatusEnum getByCode(Integer code) {
        for (OrderStatusEnum e : values()) {
            if (e.code.equals(code)) {
                return e;
            }
        }
        return null;
    }
}</code></pre>
 
<h3>8.3 使用原则</h3>
<table>
<tr><th style="width:220px">场景</th><th>处理方式</th></tr>
<tr><td>状态、类型、渠道等有固定取值集</td><td><span class="tag tag-must">必须</span>枚举类,含 code + desc + getByCode</td></tr>
<tr><td>纯数值阈值(重试次数、超时时间)</td><td>常量类 <code>static final</code> 或配置项</td></tr>
<tr><td>Redis Key 前缀、MQ Topic</td><td>常量类统一收口,禁止散落</td></tr>
<tr><td>循环下标 i/j/k、坐标 0/1</td><td>允许,不算魔法值</td></tr>
</table>
 
 
<div class="part-title">第三部分 · 数据库规范</div>
<!-- 9 -->
<h2>九、数据库设计规范</h2>
 
<h3>9.1 强制规则</h3>
<table>
<tr><th style="width:190px">规则项</th><th>要求</th></tr>
<tr><td>字符编码</td><td><b>统一 UTF-8</b>(MySQL 使用 utf8mb4,可存储 emoji),全库统一排序规则</td></tr>
<tr><td>主键</td><td><b>不使用自增长(auto_increment)</b>,统一使用分布式 ID(雪花算法);避免分库分表冲突与爬库风险</td></tr>
<tr><td>外键</td><td><b>不使用物理外键(FOREIGN KEY)</b>,关联关系由应用层维护;只建索引加速关联查询</td></tr>
<tr><td>字段长度</td><td><b>所有字段必须显式设置长度</b>(varchar 按实际业务上限设置;int 考虑 tinyint/smallint/int 精确选型),禁止不设长度</td></tr>
<tr><td>必备字段</td><td><code>id</code>、<code>create_time</code>、<code>update_time</code>、<code>is_deleted</code>(逻辑删除)</td></tr>
<tr><td>注释</td><td>表和字段必须写 COMMENT,与实体类注释保持一致</td></tr>
<tr><td>禁止</td><td>存储过程、触发器、数据库层业务逻辑</td></tr>
</table>
 
<h3>9.2 标准建表模板</h3>
<pre><code>CREATE TABLE `order_info` (
  `id`            bigint(20)    NOT NULL                COMMENT '主键ID(雪花算法生成)',
  `order_no`      varchar(32)   NOT NULL                COMMENT '订单编号(业务唯一)',
  `user_id`       bigint(20)    NOT NULL                COMMENT '用户ID(逻辑关联 user_info.id,无物理外键)',
  `order_amount`  bigint(20)    NOT NULL DEFAULT 0      COMMENT '订单金额(单位:分)',
  `order_status`  tinyint(4)    NOT NULL DEFAULT 0      COMMENT '订单状态 0-待支付 1-已支付 2-已取消 3-已完成',
  `remark`        varchar(256)  DEFAULT NULL            COMMENT '订单备注',
  `create_time`   datetime      NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time`   datetime      NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `is_deleted`    tinyint(4)    NOT NULL DEFAULT 0      COMMENT '逻辑删除 0-正常 1-已删除',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_order_no` (`order_no`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单信息表';</code></pre>
 
<h3>9.3 字段长度选型参考</h3>
<table>
<tr><th style="width:200px">数据</th><th>推荐类型与长度</th></tr>
<tr><td>主键 / 用户ID / 订单ID</td><td><code>bigint(20)</code>,雪花算法生成</td></tr>
<tr><td>订单编号</td><td><code>varchar(32)</code></td></tr>
<tr><td>手机号</td><td><code>varchar(16)</code></td></tr>
<tr><td>邮箱</td><td><code>varchar(64)</code></td></tr>
<tr><td>状态/类型</td><td><code>tinyint(4)</code>,对应枚举 code</td></tr>
<tr><td>金额</td><td><code>bigint(20)</code>,单位分;或 <code>decimal(12,2)</code></td></tr>
<tr><td>URL / 图片地址</td><td><code>varchar(512)</code></td></tr>
<tr><td>备注/描述</td><td><code>varchar(256)</code> / <code>varchar(1024)</code>,超长用 text 拆扩展表</td></tr>
</table>
 
<!-- 10 -->
<h2>十、SQL 与查询禁项规范</h2>
 
<table>
<tr><th style="width:240px">禁项</th><th>要求</th></tr>
<tr><td>SELECT *</td><td>禁止;显式列出所需字段</td></tr>
<tr><td>循环内查库(N+1)</td><td>禁止在 for / while / stream 等<b>循环代码块内查询数据库</b>(逐条 select/update/insert);改为一次性批量查询后在内存组装</td></tr>
<tr><td>复杂 SQL / 多表 JOIN</td><td>尽量减少复杂 SQL 查询;关联查询 JOIN 表数原则上<b>不超过 5 张</b>,超过 5 张必须拆分为多次查询 + 内存组装</td></tr>
<tr><td>大表全表查询</td><td>大数据量表(订单、日志、流水等)禁止无 WHERE 条件或条件不命中索引的全表查询;必须带索引条件并限制返回行数</td></tr>
<tr><td>深分页 OFFSET</td><td>大表翻页用游标:<code>WHERE id &gt; #{lastId} LIMIT n</code></td></tr>
<tr><td>无索引条件查询</td><td>WHERE / ORDER BY 字段必须命中索引,上线前 EXPLAIN 验证</td></tr>
<tr><td>左模糊 LIKE '%xxx'</td><td>不走索引;需求存在时用 ES 或全文索引方案</td></tr>
<tr><td>批量操作无上限</td><td>foreach 单批 ≤ 500 条,大批量分批提交</td></tr>
</table>
 
<h3>10.1 正反示例</h3>
<pre><code><span class="cm">// 错误:循环内逐条查库(N+1 问题)</span>
for (OrderItem item : items) {
    ProductInfo p = productMapper.selectById(item.getProductId());  <span class="cm">// 禁止:循环代码块内查询数据库</span>
}
 
<span class="cm">// 正确:一次批量查询 + 内存组装</span>
List&lt;Long&gt; productIds = items.stream().map(OrderItem::getProductId).collect(Collectors.toList());
Map&lt;Long, ProductInfo&gt; productMap = productMapper.selectBatchByIds(productIds)
        .stream().collect(Collectors.toMap(ProductInfo::getId, Function.identity()));
 
<span class="cm">// 错误:一张 SQL 关联 7 张表,难以维护、易超时,禁止</span>
SELECT o.*, u.*, p.*, c.*, s.*, a.*, r.*
FROM order_info o
JOIN user_info u    ON o.user_id = u.id
JOIN product_info p ON o.product_id = p.id
<span class="cm">// ... 继续 JOIN 至 7 张表(超过 5 张,禁止)</span>
 
<span class="cm">// 正确:拆分为多次单表/少量关联查询,内存组装结果</span>
OrderInfo order = orderMapper.selectByOrderNo(orderNo);
UserInfo user = userMapper.selectById(order.getUserId());
ProductInfo product = productMapper.selectById(order.getProductId());
 
<span class="cm">// 错误:大表无 WHERE 条件的全表查询,禁止</span>
SELECT * FROM order_info;  <span class="cm">// 全表扫描,大表直接拖垮 DB</span>
 
<span class="cm">// 正确:带索引条件 + 限制返回行数</span>
SELECT id, order_no, order_status FROM order_info
WHERE user_id = #{userId} AND create_time &gt;= #{startTime}
ORDER BY id DESC LIMIT 50;</code></pre>
 
 
<div class="part-title">第四部分 · 接口与可观测规范</div>
<!-- 11 -->
<h2>十一、接口统一返回体规范</h2>
 
<p><span class="tag tag-must">必须</span>所有接口统一返回 <code>Result&lt;T&gt;</code> 结构,禁止 Controller 各写各的返回格式。</p>
 
<h3>11.1 统一返回结构</h3>
<pre><code>{
  "code": 0,            <span class="cm">// 0=成功,非0=错误码(见12.3错误码分段)</span>
  "message": "success", <span class="cm">// 提示信息,可直接展示给用户</span>
  "data": { }           <span class="cm">// 业务数据,失败时为 null</span>
}</code></pre>
 
<h3>11.2 规则</h3>
<ul>
<li><code>Result</code> 定义在 common 模块,全工程唯一,禁止每个服务自定义一套;</li>
<li>分页返回统一 <code>data = { list, total, pageNum, pageSize }</code>;</li>
<li>金额字段用分(long)传输,时间字段统一毫秒时间戳,全局约定一致;</li>
<li>成功返回 <code>Result.success(data)</code>,失败抛 BusinessException 由全局异常处理器转 Result,Controller 内禁止手写 try-catch 拼 error 返回。</li>
</ul>
 
<!-- 12 -->
<h2>十二、全局异常处理规范</h2>
 
<p><span class="tag tag-must">必须</span>使用 <code>@RestControllerAdvice</code> 全局异常处理器统一捕获,Controller / Service 内禁止散落 try-catch 拼 JSON。</p>
 
<h3>12.1 异常分类</h3>
<table>
<tr><th style="width:180px">类型</th><th>说明</th><th>处理方式</th></tr>
<tr><td>BusinessException</td><td>可预期业务异常(参数错、状态非法)</td><td>抛出 → 全局捕获 → 返回错误码 + 友好提示</td></tr>
<tr><td>ValidationException</td><td>参数校验异常</td><td>由 <code>@Valid</code> 触发,全局捕获返回字段级提示</td></tr>
<tr><td>ThirdPartyException</td><td>第三方/RPC 调用失败</td><td>封装为业务异常,核心链路配降级</td></tr>
<tr><td>其他 RuntimeException</td><td>不可预期系统异常</td><td>全局兜底,记 ERROR 日志,返回"系统繁忙"</td></tr>
</table>
 
<h3>12.2 规则</h3>
<ul>
<li>异常日志必须包含完整上下文(入参、traceId、用户标识),堆栈对象作为日志最后一个参数:<code>log.error("msg:{}", ctx, e)</code>;</li>
<li>禁止 <code>catch (Exception e)</code> 后吞掉不处理、不打日志;</li>
<li>禁止在循环内抛异常做流程控制;</li>
<li>对外错误信息禁止暴露内部细节(表名、SQL、堆栈)。</li>
</ul>
 
<h3>12.3 错误码分段</h3>
<table>
<tr><th style="width:120px">码段</th><th>含义</th><th>示例</th></tr>
<tr><td>0</td><td>成功</td><td>—</td></tr>
<tr><td>1xxxx</td><td>通用错误(参数/鉴权/限流)</td><td>10001 参数缺失</td></tr>
<tr><td>2xxxx</td><td>用户域</td><td>20001 用户不存在</td></tr>
<tr><td>3xxxx</td><td>订单域</td><td>30001 订单状态非法</td></tr>
<tr><td>4xxxx</td><td>支付域</td><td>40001 支付超时</td></tr>
<tr><td>5xxxx</td><td>第三方服务</td><td>50001 短信通道失败</td></tr>
<tr><td>9xxxx</td><td>系统级</td><td>99999 系统繁忙</td></tr>
</table>
 
<!-- 13 -->
<h2>十三、日志规范</h2>
 
<h3>13.1 框架与级别</h3>
<ul>
<li>统一 SLF4J + Logback,<code>@Slf4j</code> 注解声明;<span class="tag tag-must">必须</span>禁止 <code>System.out.println</code>;</li>
</ul>
<table>
<tr><th style="width:110px">级别</th><th>使用场景</th></tr>
<tr><td>ERROR</td><td>系统异常、影响业务的错误、第三方调用失败</td></tr>
<tr><td>WARN</td><td>可恢复异常、降级、容错、敏感操作警告</td></tr>
<tr><td>INFO</td><td>关键业务节点(下单、支付、登录),带业务上下文</td></tr>
<tr><td>DEBUG</td><td>调试细节,生产默认关闭;禁止循环内打 INFO</td></tr>
</table>
 
<h3>13.2 格式要求</h3>
<pre><code><span class="cm">// 错误:拼接 + 无上下文 + 丢堆栈</span>
log.info("下单成功");
log.error("错误:" + e.getMessage());
 
<span class="cm">// 正确:占位符 + 业务标记 + 上下文 + 完整堆栈</span>
log.info("[ORDER_CREATE] userId={}, productId={}, amount={}", userId, productId, amount);
log.error("[ORDER_CREATE] create failed, dto={}", dto, e);</code></pre>
<ul>
<li>关键业务日志带 <code>[业务标记]</code> 前缀,便于按场景检索;</li>
<li>traceId 由 MDC 注入贯穿全链路;</li>
<li>手机号、身份证、密码等敏感字段强制脱敏。</li>
</ul>
 
 
<div class="part-title">第五部分 · 稳定性与性能规范</div>
<!-- 14 -->
<h2>十四、线程池规范</h2>
 
<ul>
<li><span class="tag tag-must">必须</span>禁止裸 <code>new Thread()</code>,统一通过 <code>ThreadPoolExecutor</code> 显式创建,禁止 <code>Executors.newFixedThreadPool / newCachedThreadPool</code>(无界队列 OOM 风险);</li>
<li>线程池必须自定义 ThreadFactory 命名(如 <code>order-pay-pool-%d</code>),便于线程栈排查;</li>
<li>核心数 / 最大数 / 队列容量 / 拒绝策略必须按业务评估显式配置,拒绝策略须记录日志或有兜底;</li>
<li>线程池参数收口到 Nacos 配置,可动态调整(配置变更按第十九条同步归档);</li>
<li>共享可变状态用 <code>ConcurrentHashMap</code> 等并发容器;<code>SimpleDateFormat</code> 换 <code>DateTimeFormatter</code>。</li>
</ul>
 
<pre><code>ThreadPoolExecutor executor = new ThreadPoolExecutor(
        4, 8, 60, TimeUnit.SECONDS,
        new LinkedBlockingQueue&lt;&gt;(1000),
        new ThreadFactoryBuilder().setNameFormat("order-pay-pool-%d").build(),
        new ThreadPoolExecutor.CallerRunsPolicy());</code></pre>
 
<!-- 15 -->
<h2>十五、幂等规范</h2>
 
<ul>
<li><span class="tag tag-must">必须</span>创建类接口(下单、支付发起、退款申请)支持幂等 key:客户端生成唯一键,服务端重复请求直接返回首次结果;</li>
<li>支付回调、MQ 消费强制幂等:以业务单号 + 状态做防重,处理前先查处理结果;</li>
<li>状态流转幂等:重复触发"已支付→已取消"类非法流转返回明确错误而非静默成功;</li>
<li>幂等实现优先 Redis setnx(带 TTL),强一致场景用数据库唯一索引兜底;</li>
<li>更新类接口带版本号(乐观锁):<code>UPDATE ... SET version = version + 1 WHERE id = ? AND version = ?</code>。</li>
</ul>
 
 
<div class="part-title">第六部分 · 安全规范</div>
<!-- 16 -->
<h2>十六、鉴权与越权防护规范</h2>
 
<ul>
<li><span class="tag tag-must">必须</span>所有对外接口鉴权,白名单仅限登录、健康检查,白名单显式配置并评审;</li>
<li>鉴权统一由框架层(拦截器 / 网关)完成,权限注解化:<code>@RequiresPermissions("order:cancel")</code>;</li>
<li><b>资源级越权校验:</b>按 ID 操作资源(查订单、改地址)时,必须校验资源归属于当前用户,禁止只校验登录态;</li>
<li>用户角色 / 权限变更后旧 token 处理策略明确(踢下线或短有效期);</li>
<li>日志与监控不记录完整 token / 密码。</li>
</ul>
 
<pre><code><span class="cm">// 错误:只校验登录,未校验归属 → 水平越权</span>
public OrderDetailVO getOrderDetail(String orderNo) {
    return orderMapper.selectByOrderNo(orderNo);  <span class="cm">// 任意登录用户可查任意订单</span>
}
 
<span class="cm">// 正确:归属校验</span>
public OrderDetailVO getOrderDetail(Long userId, String orderNo) {
    OrderInfo order = orderMapper.selectByOrderNo(orderNo);
    if (order == null || !userId.equals(order.getUserId())) {
        throw new BusinessException(OrderErrorCode.ORDER_NOT_EXIST);
    }
    return convert(order);
}</code></pre>
 
<!-- 17 -->
<h2>十七、防注入规范</h2>
 
<table>
<tr><th style="width:170px">风险点</th><th>防护要求</th></tr>
<tr><td>SQL 注入</td><td>MyBatis 统一 <code>#{}</code> 预编译;<code>${}</code> 禁用(动态表名/排序字段除外,且必须白名单校验)</td></tr>
<tr><td>XSS</td><td>入参富文本白名单过滤,输出转义</td></tr>
<tr><td>文件上传</td><td>类型/大小校验、重命名存储、上传与访问域名隔离</td></tr>
<tr><td>反序列化</td><td>禁止反序列化不可信数据,统一 JSON</td></tr>
<tr><td>命令注入</td><td>禁止 <code>Runtime.exec</code> 拼接外部输入</td></tr>
</table>
 
 
<div class="part-title">第七部分 · 测试规范</div>
<!-- 18 -->
<h2>十八、单元测试规范</h2>
 
<ul>
<li>核心业务(订单、支付、状态流转)、工具类、复杂算法必须有单测,行覆盖率 ≥ 70%;</li>
<li>测试与生产代码同包结构,命名 <code>原类名 + Test</code>(<code>OrderServiceImplTest</code>);</li>
<li>单测不依赖真实数据库 / Redis / 第三方,外部依赖 Mock(Mockito);</li>
<li>单测方法名表达场景:<code>createOrder_shouldThrow_whenProductOffShelf</code>;</li>
<li>边界用例必备:null 入参、空集合、金额 0 / 负数、超长字符串、并发重复请求;</li>
<li>单测随代码同一次提交 Git,commit 标注:<code>[订单] feat: 新增取消接口(含单测)</code>。</li>
</ul>
 
 
<div class="part-title">第八部分 · 版本管理与 AI 协作规范</div>
<!-- 19 -->
<h2>十九、Git 提交与配套产物同步规范</h2>
 
<h3>19.1 每日提交要求</h3>
<table>
<tr><th style="width:180px">要求</th><th>说明</th></tr>
<tr><td>每日必须提交</td><td>代码<b>每日必须提交 Git</b>,禁止长期本地囤积;下班前将当日可编译通过的代码推送远端</td></tr>
<tr><td>提交粒度</td><td>按功能点提交,一次提交对应一个明确改动;禁止一天改动堆成一个大提交</td></tr>
<tr><td>可编译</td><td>提交到共享分支(dev/release)的代码必须可编译、可启动</td></tr>
</table>
 
<h3>19.2 提交备注(Commit Message)规范</h3>
<p>备注必须<b>写清修改内容</b>,格式:<code>[模块] 类型: 修改内容</code></p>
 
<table>
<tr><th style="width:120px">类型</th><th>含义</th><th style="width:420px">示例</th></tr>
<tr><td>feat</td><td>新功能</td><td><code>[订单] feat: 新增订单创建接口</code></td></tr>
<tr><td>fix</td><td>缺陷修复</td><td><code>[订单] fix: 修复订单金额计算溢出问题</code></td></tr>
<tr><td>refactor</td><td>重构</td><td><code>[用户] refactor: 抽离手机号校验公共方法</code></td></tr>
<tr><td>db</td><td>数据库变更</td><td><code>[订单] db: order_info 新增支付渠道字段(附DDL)</code></td></tr>
<tr><td>config</td><td>配置变更</td><td><code>[订单] config: 更新nacos订单超时配置(附配置文件)</code></td></tr>
</table>
 
<pre><code><span class="cm">// 错误:无法追溯</span>
git commit -m "修改"
git commit -m "fix bug"
git commit -m "更新代码"
 
<span class="cm">// 正确:模块 + 类型 + 具体内容</span>
git commit -m "[订单] feat: 新增订单取消接口,超时未支付自动取消"
git commit -m "[用户] fix: 修复登录token刷新并发覆盖问题"</code></pre>
 
<h3>19.3 数据库 DDL 同步提交</h3>
<p><span class="tag tag-must">必须</span>凡是涉及数据库修改(新增表、加字段、改索引等),DDL 脚本必须<b>与代码同一次提交</b>入库:</p>
 
<ul>
<li>DDL 文件统一放在工程 <code>doc/sql/</code>(或 <code>sql/ddl/</code>)目录,按日期 + 序号命名:<code>20260824_01_add_pay_channel_to_order_info.sql</code></li>
<li>DDL 内容包含完整的变更语句与回滚语句,表结构变更同步更新表 COMMENT</li>
<li>禁止只在测试库手工改表而代码库无 DDL 记录——环境无法重建,事故无法追溯</li>
</ul>
 
<pre><code><span class="cm">-- 20260824_01_add_pay_channel_to_order_info.sql</span>
-- 变更:order_info 新增支付渠道字段
ALTER TABLE `order_info`
    ADD COLUMN `pay_channel` tinyint(4) NOT NULL DEFAULT 0 COMMENT '支付渠道 0-微信 1-支付宝 2-余额' AFTER `order_status`;
 
<span class="cm">-- 回滚</span>
ALTER TABLE `order_info` DROP COLUMN `pay_channel`;</code></pre>
 
<h3>19.4 Nacos 配置同步提交</h3>
<p><span class="tag tag-must">必须</span>凡是使用 Nacos 配置中心,修改配置后必须<b>同步提交配置文件</b>到代码库:</p>
 
<ul>
<li>配置文件按环境归档:<code>doc/nacos/{dev|test|prod}/xxx-service.yaml</code>,与 Nacos 控制台内容保持一致</li>
<li>在 Nacos 控制台改配置的同时(或当日)提交对应文件,commit 标注 <code>config</code> 类型与改动项</li>
<li>敏感信息(密码、密钥)在归档文件中脱敏,并在文件头注明“脱敏归档,真实值见 Nacos”</li>
<li>上线检查清单必须包含:代码 ✓ / DDL ✓ / Nacos 配置文件 ✓ 三者齐备才可发版</li>
</ul>
 
<div class="warn"><b>发版自检清单:</b>① 当日代码已提交并推送 &nbsp;② commit 备注写明修改内容 &nbsp;③ 数据库变更已附 DDL 脚本 &nbsp;④ Nacos 改动已同步归档配置文件</div>
 
<!-- 20 -->
<h2>二十、AI 协作:新功能开发文档先行</h2>
 
<p><span class="tag tag-must">必须</span>AI 编写新功能点时,<b>必须先生成开发文档,人工确认文档没问题后,再生成代码</b>。禁止跳过文档直接产出代码。</p>
 
<h3>20.1 标准流程</h3>
<pre><code>需求输入
   │
   ▼
① AI 生成开发文档(接口设计、表结构、业务流程、影响范围)
   │
   ▼
② 人工评审开发文档 ── 不通过 ──→ 补充/修正文档,重新评审
   │ 通过
   ▼
③ AI 按已确认的文档生成代码
   │
   ▼
④ 人工 Code Review + 测试验证</code></pre>
 
<h3>20.2 开发文档必备内容</h3>
<table>
<tr><th style="width:160px">章节</th><th>要求</th></tr>
<tr><td>功能概述</td><td>背景、目标、用户故事</td></tr>
<tr><td>接口设计</td><td>URL、方法、入参/出参字段表、错误码</td></tr>
<tr><td>数据库设计</td><td>新表 DDL / 变更字段 DDL(含回滚语句,遵循第九条规范)</td></tr>
<tr><td>业务流程</td><td>核心流程步骤说明(与代码 STEP 注释一一对应)</td></tr>
<tr><td>枚举与状态</td><td>新增/变更的枚举定义(遵循第八条规范)</td></tr>
<tr><td>影响范围</td><td>涉及的模块、上下游接口、Nacos 配置变更项</td></tr>
</table>
 
<div class="note"><b>未确认文档产出的代码视为无效产出</b>,不进入 Code Review 流程,需按确认后的文档重新生成。</div>
 
<!-- 21 -->
<h2>二十一、AI 协作:功能修改文档先改</h2>
 
<p><span class="tag tag-must">必须</span>AI 修改已有功能时,<b>必须先修改开发文档,文档确认没问题后,再修改代码</b>,保证文档与代码始终一致。</p>
 
<h3>21.1 标准流程</h3>
<ol>
<li><b>改文档:</b>AI 先定位对应功能的开发文档,修改受影响的章节(接口字段、业务流程、枚举、DDL);</li>
<li><b>人工确认:</b>评审文档变更是否与修改意图一致;</li>
<li><b>改代码:</b>确认通过后,AI 按更新后的文档修改代码;</li>
<li><b>一致性校验:</b>Code Review 时同步核对"文档描述 = 代码实现"。</li>
</ol>
 
<div class="warn"><b>红线:</b>禁止"只改代码不改文档";文档与实现不一致时,以文档评审结论为准修正代码。</div>
 
<!-- 22 -->
<h2>二十二、AI 协作:开发文档同步提交 Git</h2>
 
<p><span class="tag tag-must">必须</span>AI 编写的开发文档与代码<b>一并提交到 Git</b>,纳入版本管理,与代码同仓库、同分支、同节奏。</p>
 
<h3>22.1 文档归档规则</h3>
<table>
<tr><th style="width:220px">类型</th><th>路径约定</th></tr>
<tr><td>功能开发文档</td><td><code>doc/design/{模块}_{功能}_{日期}.md</code>,例:<code>doc/design/order_cancel_20260824.md</code></td></tr>
<tr><td>数据库 DDL</td><td><code>doc/sql/</code>(按第十九条规范,与文档引用的 DDL 为同一份)</td></tr>
<tr><td>Nacos 配置归档</td><td><code>doc/nacos/{env}/</code>(按第十九条规范)</td></tr>
</table>
 
<h3>22.2 提交要求</h3>
<ul>
<li>开发文档与对应代码<b>同一次提交</b>(或文档先行提交),commit 备注标注文档变更:<code>[订单] feat: 新增订单取消接口(含开发文档 doc/design/order_cancel_20260824.md)</code></li>
<li>修改功能的场景,文档变更与代码变更<b>同一次提交</b>,保证任意 commit 节点文档与代码可对齐回溯;</li>
<li>文档使用 Markdown 格式,随功能演进持续更新,禁止归档后失管。</li>
</ul>
 
<div class="part-title">第九部分 · 部署规范</div>
<!-- 23 -->
<h2>二十三、部署文档规范</h2>
 
<p><span class="tag tag-must">必须</span>项目部署必须编写<b>部署文档</b>,与项目同仓库归档(<code>doc/deploy/{项目名}_{环境}_部署文档.md</code>)。部署文档是项目可交付的一部分:任何一名新成员仅凭该文档即可完成部署、排障与恢复,禁止"只在部署者脑中"的隐性部署知识。</p>
 
<h3>23.1 部署文档必备内容</h3>
<table>
<tr><th style="width:150px">章节</th><th>要求</th></tr>
<tr><td>项目部署路径</td><td>项目(应用包、前端资源)在服务器上的完整部署路径,例:<code>/opt/java/app.jar</code>、<code>/opt/web/dist</code>;注明所属服务器 IP 与用途</td></tr>
<tr><td>组件部署路径</td><td>所有依赖组件(Nginx、MySQL、Redis、MQ、JDK、Nacos 等)的安装/数据/配置文件路径,例:<code>/etc/nginx/nginx.conf</code>、<code>/etc/redis.conf</code>、<code>/etc/my.cnf</code>、docker 容器名</td></tr>
<tr><td>版本号</td><td>项目版本(jar 版本 / 镜像 tag / 分支 commit)与各组件版本(JDK、MySQL、Redis、Nginx、Nacos),升级须同步更新</td></tr>
<tr><td>启动/停止命令</td><td>项目和各组件的启动、停止、重启、查看状态、查看日志命令;docker 部署写明容器名与 <code>docker run</code> 完整参数或 compose 文件路径</td></tr>
<tr><td>账号密码</td><td>服务器 SSH 账号、数据库账号密码、Redis 密码、中间件控制台账号等;敏感信息在文档中脱敏,明文密码存放于受控的密码管理渠道,文档中写明获取方式</td></tr>
<tr><td>注意事项</td><td>部署前置条件(DDL 执行顺序、Nacos 配置项)、端口开放、防火墙、启动依赖顺序、已知坑与回滚方案</td></tr>
</table>
 
<h3>23.2 部署文档模板</h3>
<pre><code># {项目名} 部署文档
 
## 1. 基本信息
- 服务器:{IP}(用途:生产/测试)
- 项目版本:v1.2.0(分支 master / commit abc1234)
- 组件版本:JDK 1.8 / MySQL 8.0 / Redis 6.2 / Nginx 1.24 / Nacos 2.2
 
## 2. 部署路径
| 对象 | 路径 | 说明 |
|---|---|---|
| 应用 jar | /opt/java/app.jar | Spring Boot 应用 |
| 前端资源 | /opt/web/dist | Vue 构建产物 |
| Nginx 配置 | /etc/nginx/nginx.conf | 反向代理 |
| MySQL | docker 容器 mysql-8.0,数据 /data/mysql | 持久化目录 |
| Redis | docker 容器 redis,配置 /etc/redis.conf | 密码见第5节 |
 
## 3. 启动与停止
- 应用启动:cd /opt/java &amp;&amp; nohup java -jar app.jar --spring.profiles.active=prod &gt; app.log 2&gt;&amp;1 &amp;
- 应用停止:ps -ef | grep app.jar | grep -v grep | awk '{print $2}' | xargs kill
- 组件重启:docker restart mysql-8.0 / docker restart redis
- 日志查看:tail -f /opt/java/app.log;docker logs -f --tail 200 mysql-8.0
 
## 4. 端口与依赖
- 端口:80(Nginx)、8080(应用)、3306(MySQL)、6379(Redis)
- 启动顺序:MySQL → Redis → Nacos → 应用 → Nginx
 
## 5. 账号密码(脱敏,明文见密码管理渠道 {渠道名})
- SSH:devops / ********
- MySQL:root / ********(业务库 {db_name})
- Redis:requirepass ********
 
## 6. 注意事项
- 部署前先执行 doc/sql/ 下新增 DDL(按文件名日期顺序)
- 新增 Nacos 配置项需同步更新 doc/nacos/prod/ 归档
- 回滚:保留上一版本 app.jar.bak,替换后重启即可</code></pre>
 
<h3>23.3 更新与提交要求</h3>
<ul>
<li><span class="tag tag-must">必须</span>部署结构发生变化(换路径、换组件、改端口、改启动方式)时,<b>同步更新部署文档</b>,与代码同一次提交 Git;</li>
<li><span class="tag tag-must">必须</span>首次部署、环境迁移、组件升级后,由未参与部署的成员按文档验证一次可复现性;</li>
<li><span class="tag tag-should">应当</span>将部署文档链接写入项目 README,保证新人可直接定位;</li>
<li><span class="tag tag-must">必须</span>文档中账号密码脱敏展示,明文密码统一放密码管理渠道(如公司密码库),文档只写获取方式,禁止明文密码入 Git。</li>
</ul>
 
<!-- 附录 -->
<h2>附录一:Code Review 检查清单</h2>
 
<table>
<tr><th style="width:60px">序号</th><th>检查项</th><th style="width:90px">级别</th></tr>
<tr><td colspan="3" style="background:#eef3ff;font-weight:600">一、工程结构</td></tr>
<tr><td>1</td><td>Controller 无业务逻辑;业务逻辑在 Service;SQL 在 Mapper</td><td>必须</td></tr>
<tr><td colspan="3" style="background:#eef3ff;font-weight:600">二、编码规范</td></tr>
<tr><td>2</td><td>类名、实体类名为标准大驼峰,见名知意</td><td>必须</td></tr>
<tr><td>3</td><td>方法名能表达意图,无 handle/query1 类无意义命名</td><td>必须</td></tr>
<tr><td>4</td><td>实体类有类注释 + 全部字段注释,状态字段标注枚举取值</td><td>必须</td></tr>
<tr><td>5</td><td>方法有完整 Javadoc;核心业务有 STEP 分步流程注释</td><td>必须</td></tr>
<tr><td>6</td><td>单方法体 ≤ 300 行;重复代码已抽公共方法</td><td>必须</td></tr>
<tr><td>7</td><td>无魔法值;状态/类型已收口到枚举类</td><td>必须</td></tr>
<tr><td colspan="3" style="background:#eef3ff;font-weight:600">三、数据库规范</td></tr>
<tr><td>8</td><td>建表 UTF-8(utf8mb4)、无外键、字段长度显式、主键非自增(雪花ID)</td><td>必须</td></tr>
<tr><td>9</td><td>无 SELECT *、无循环内查库、JOIN 不超过 5 张表、大表禁止全表查询、深分页用游标、条件命中索引</td><td>必须</td></tr>
<tr><td colspan="3" style="background:#eef3ff;font-weight:600">四、接口与可观测</td></tr>
<tr><td>10</td><td>接口统一返回 Result&lt;T&gt;,分页结构统一</td><td>必须</td></tr>
<tr><td>11</td><td>异常由全局处理器统一捕获,错误码分段,无散落 try-catch</td><td>必须</td></tr>
<tr><td>12</td><td>日志占位符写法、带业务标记与上下文、敏感字段脱敏</td><td>必须</td></tr>
<tr><td colspan="3" style="background:#eef3ff;font-weight:600">五、稳定性与性能</td></tr>
<tr><td>13</td><td>无裸 new Thread,线程池命名 + 显式参数 + 有界队列</td><td>必须</td></tr>
<tr><td>14</td><td>创建类接口 / 回调 / MQ 消费已实现幂等</td><td>必须</td></tr>
<tr><td colspan="3" style="background:#eef3ff;font-weight:600">六、安全规范</td></tr>
<tr><td>15</td><td>接口已鉴权,按 ID 操作资源已做归属校验(防越权)</td><td>必须</td></tr>
<tr><td>16</td><td>SQL 全部 #{} 预编译,${} 动态字段已白名单校验</td><td>必须</td></tr>
<tr><td colspan="3" style="background:#eef3ff;font-weight:600">七、测试规范</td></tr>
<tr><td>17</td><td>核心业务有单测,覆盖率 ≥ 70%,随代码同提交</td><td>必须</td></tr>
<tr><td colspan="3" style="background:#eef3ff;font-weight:600">八、版本管理与 AI 协作</td></tr>
<tr><td>18</td><td>每日代码已提交 Git,commit 备注写明修改内容</td><td>必须</td></tr>
<tr><td>19</td><td>数据库变更有 DDL 脚本同步提交(含回滚语句)</td><td>必须</td></tr>
<tr><td>20</td><td>Nacos 配置变更已同步归档配置文件(敏感项脱敏)</td><td>必须</td></tr>
<tr><td>21</td><td>AI 新功能:开发文档已人工确认后才生成的代码</td><td>必须</td></tr>
<tr><td>22</td><td>AI 修改功能:开发文档已先于代码更新并确认,文档与实现一致</td><td>必须</td></tr>
<tr><td colspan="3" style="background:#eef3ff;font-weight:600">九、部署规范</td></tr>
<tr><td>23</td><td>部署文档完整(部署路径/组件路径/版本号/启动命令/账号密码/注意事项),结构变更时与代码同提交,密码已脱敏</td><td>必须</td></tr>
</table>
 
<h2>附录二:AI 协作开发流程总览</h2>
 
<pre><code>新功能:需求 → ① AI生成开发文档 → ② 人工确认文档 → ③ AI生成代码 → ④ Code Review → ⑤ 文档+DDL+配置+代码 一并提交 Git
修改功能:变更需求 → ① AI先改开发文档 → ② 人工确认文档 → ③ AI按文档改代码 → ④ Review核对文档与实现一致 → ⑤ 一并提交 Git</code></pre>
 
<p class="footer">Java 服务端开发标准 v1.5 &nbsp;|&nbsp; 2026-08-24 发布 &nbsp;|&nbsp; 修订记录:v1.0 初版(10 条核心规则);v1.1 新增第 11~13 条 AI 协作流程规范;v1.2 新增第 14~22 条(统一返回体、全局异常、日志、SQL 禁项、线程池、鉴权越权、防注入、幂等、单元测试);v1.3 按归类重排为八大部分,章节编号连续化(1~22);v1.4 新增第九部分部署规范(第 23 条:部署文档必备内容与模板);v1.5 第十条 SQL 与查询禁项新增「循环内查库、复杂 SQL JOIN 表数上限(≤5)、大表禁止全表查询」校验规则及正反示例</p>
 
</body>
</html>