<!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 | 版本:v1.5 | 生效日期: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<OrderDetailVO> 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<Order> query1(Long userId) { }
|
public boolean doCheck(Object o) { }
|
|
<span class="cm">// 正确:方法名即文档</span>
|
public void payOrder(Order order) { }
|
public List<Order> 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<OrderInfo> 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 > #{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<Long> productIds = items.stream().map(OrderItem::getProductId).collect(Collectors.toList());
|
Map<Long, ProductInfo> 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 >= #{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<T></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<>(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>① 当日代码已提交并推送 ② commit 备注写明修改内容 ③ 数据库变更已附 DDL 脚本 ④ 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 && nohup java -jar app.jar --spring.profiles.active=prod > app.log 2>&1 &
|
- 应用停止: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<T>,分页结构统一</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 | 2026-08-24 发布 | 修订记录: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>
|