feat: update documentation and component demos for backend layered architecture

- Add new LanguageScopeDemo component for backend languages overview
- Refactor and simplify existing demo components (ControllerLayerDemo, DtoFlowDemo, DependencyDirectionDemo)
- Update .gitignore to exclude .claude/skills directory
- Modify backend-related sections in documentation from "后端与全栈" to "后端开发"
- Add new backend layered architecture demo components (CleanArchitectureDemo, DependencyDirectionDemo)
- Improve documentation structure and content for stage-3 core skills
- Fix component initialization timing in CompileVsInterpretDemo and RateLimiterDemo
- Add design style prompt reference in frontend documentation
This commit is contained in:
sanbuphy
2026-03-01 12:28:47 +08:00
parent d8eb93663d
commit dc8b5773f1
22 changed files with 2660 additions and 5288 deletions
@@ -1,362 +1,113 @@
<template>
<div class="dto-flow-demo">
<div class="demo-header">
<h4>🔄 DTO 流转数据在不同层之间的转换</h4>
<p class="subtitle">
DTOData Transfer Object是层与层之间传递数据的载体
</p>
<div class="dto-demo">
<div class="header">
<div class="title">DTO 流转数据在不同层之间的转换</div>
<div class="subtitle">DTOData Transfer Object是层与层之间传递数据的载体</div>
</div>
<!-- 流程图 -->
<div class="flow-diagram">
<div class="flow-step">
<div class="step-title">
Controller
</div>
<div class="step-code">
<div class="code-line">
<span class="comment">// 接收 Request DTO</span>
</div>
<div class="code-line">
<span class="keyword">public</span> ResponseEntity&lt;UserDTO&gt; createUser(
</div>
<div class="code-line">
&nbsp;&nbsp;@RequestBody <span class="highlight">@Valid UserCreateRequest request</span>
</div>
<div class="code-line">
) { ... }
</div>
</div>
<div class="flow-box">
<div class="flow-step green">
<div class="step-label">Controller </div>
<pre class="step-code"><code>// 接收 Request DTO
public ResponseEntity&lt;UserDTO&gt; createUser(
@RequestBody @Valid UserCreateRequest request) { ... }</code></pre>
</div>
<div class="flow-arrow">
转换为 Service 需要的参数
<div class="arrow"> 转换为 Service 需要的参数</div>
<div class="flow-step orange">
<div class="step-label">Service </div>
<pre class="step-code"><code>public UserDTO createUser(UserCreateParam param) {
User user = param.toEntity(); // 转换为 Entity
userRepository.save(user);
return UserDTO.from(user); // Entity → DTO
}</code></pre>
</div>
<div class="arrow"> 转换为 Repository 需要的 Entity</div>
<div class="flow-step blue">
<div class="step-label">Repository </div>
<pre class="step-code"><code>public interface UserRepository
extends JpaRepository&lt;User, Long&gt; { }</code></pre>
</div>
<div class="arrow"> 返回 Entity转换为 DTO</div>
<div class="flow-step">
<div class="step-title">
Service
</div>
<div class="step-code">
<div class="code-line">
<span class="comment">// 业务处理</span>
</div>
<div class="code-line">
<span class="keyword">public</span> UserDTO createUser(UserCreateParam param) {
</div>
<div class="code-line">
&nbsp;&nbsp;<span class="comment">// 转换为 Entity</span>
</div>
<div class="code-line">
&nbsp;&nbsp;User user = <span class="highlight">param.toEntity()</span>;
</div>
<div class="code-line">
&nbsp;&nbsp;userRepository.save(user);
</div>
<div class="code-line">
&nbsp;&nbsp;<span class="keyword">return</span> <span class="highlight">UserDTO.from(user)</span>;
</div>
<div class="code-line">
}
</div>
</div>
</div>
<div class="flow-arrow">
转换为 Repository 需要的 Entity
</div>
<div class="flow-step">
<div class="step-title">
Repository
</div>
<div class="step-code">
<div class="code-line">
<span class="comment">// 数据持久化</span>
</div>
<div class="code-line">
<span class="keyword">public interface</span> UserRepository
</div>
<div class="code-line">
&nbsp;&nbsp;<span class="keyword">extends</span> JpaRepository&lt;<span class="highlight">User</span>, Long&gt; {
</div>
<div class="code-line">
}
</div>
</div>
</div>
<div class="flow-arrow">
返回 Entity转换为 DTO
</div>
<div class="flow-step">
<div class="step-title">
返回给客户端
</div>
<div class="step-code">
<div class="code-line">
<span class="comment">// Response DTO</span>
</div>
<div class="code-line">
{
</div>
<div class="code-line">
&nbsp;&nbsp;<span class="string">"id"</span>: 10001,
</div>
<div class="code-line">
&nbsp;&nbsp;<span class="string">"username"</span>: <span class="string">"张三"</span>,
</div>
<div class="code-line">
&nbsp;&nbsp;<span class="string">"email"</span>: <span class="string">"zhangsan@example.com"</span>,
</div>
<div class="code-line">
&nbsp;&nbsp;<span class="string">"createdAt"</span>: <span class="string">"2024-01-15T10:30:00Z"</span>
</div>
<div class="code-line">
}
</div>
</div>
<div class="step-label">返回给客户端</div>
<pre class="step-code"><code>{ "id": 10001, "username": "张三",
"email": "zhangsan@example.com", "createdAt": "2024-01-15T10:30:00Z" }</code></pre>
</div>
</div>
<!-- 不同层 DTO 对比 -->
<div class="dto-comparison">
<h5>📋 不同层的 DTO 职责</h5>
<div class="comparison-table">
<div class="table-header">
<div class="col-layer">
层级
</div>
<div class="col-dto">
DTO 类型
</div>
<div class="col-purpose">
职责
</div>
<div class="col-example">
示例
</div>
</div>
<div class="table-row">
<div class="col-layer">
<span class="layer-tag controller">Controller</span>
</div>
<div class="col-dto">
Request / Response DTO
</div>
<div class="col-purpose">
定义 API 契约参数校验序列化
</div>
<div class="col-example">
<code>UserCreateRequest</code>
</div>
</div>
<div class="table-row">
<div class="col-layer">
<span class="layer-tag service">Service</span>
</div>
<div class="col-dto">
Param / Result DTO
</div>
<div class="col-purpose">
封装业务方法参数解耦 Controller Service
</div>
<div class="col-example">
<code>UserCreateParam</code>
</div>
</div>
<div class="table-row">
<div class="col-layer">
<span class="layer-tag repository">Repository</span>
</div>
<div class="col-dto">
Entity / DO
</div>
<div class="col-purpose">
映射数据库表结构ORM 映射
</div>
<div class="col-example">
<code>UserEntity</code>
</div>
</div>
</div>
<div class="table-box">
<div class="table-title">不同层的 DTO 职责</div>
<table>
<thead>
<tr><th>层级</th><th>DTO 类型</th><th>职责</th><th>示例</th></tr>
</thead>
<tbody>
<tr v-for="r in rows" :key="r.layer">
<td><span :class="['tag', r.cls]">{{ r.layer }}</span></td>
<td>{{ r.type }}</td>
<td>{{ r.purpose }}</td>
<td><code>{{ r.example }}</code></td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const viewMode = ref('conversion')
const rows = [
{ layer: 'Controller', cls: 'green', type: 'Request / Response DTO', purpose: '定义 API 契约、参数校验', example: 'UserCreateRequest' },
{ layer: 'Service', cls: 'orange', type: 'Param / Result DTO', purpose: '封装业务方法参数,解耦层间依赖', example: 'UserCreateParam' },
{ layer: 'Repository', cls: 'blue', type: 'Entity / DO', purpose: '映射数据库表结构', example: 'UserEntity' }
]
</script>
<style scoped>
.dto-flow-demo {
padding: 24px;
background: linear-gradient(135deg, #f0f7ff 0%, #e6f0ff 100%);
border-radius: 12px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.dto-demo { padding: 20px; background: var(--vp-c-bg-soft); border-radius: 12px; }
.header { text-align: center; margin-bottom: 20px; }
.title { font-size: 16px; font-weight: 600; color: var(--vp-c-text-1); }
.subtitle { font-size: 13px; color: var(--vp-c-text-3); margin-top: 4px; }
.demo-header {
text-align: center;
margin-bottom: 24px;
.flow-box {
padding: 18px; border-radius: 10px; margin-bottom: 16px;
background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider);
}
.demo-header h4 {
margin: 0 0 8px 0;
color: #1a1a2e;
font-size: 18px;
}
.subtitle {
margin: 0;
color: #666;
font-size: 13px;
}
.flow-diagram {
background: white;
border-radius: 10px;
padding: 24px;
margin-bottom: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
}
.flow-step {
background: #f8f9fa;
border-radius: 6px;
overflow: hidden;
border-left: 4px solid #409eff;
border-radius: 6px; overflow: hidden;
background: var(--vp-c-bg-soft); border-left: 3px solid var(--vp-c-divider);
}
.flow-step.green { border-left-color: #10b981; }
.flow-step.orange { border-left-color: #f59e0b; }
.flow-step.blue { border-left-color: #3b82f6; }
.flow-step:nth-child(odd) {
border-left-color: #67c23a;
.step-label {
padding: 10px 14px; font-weight: 600; font-size: 13px;
color: var(--vp-c-text-1); border-bottom: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg);
}
.step-title {
padding: 12px 16px;
background: white;
font-weight: 600;
color: #303133;
font-size: 14px;
border-bottom: 1px solid #ebeef5;
}
.step-code {
padding: 16px;
font-family: 'Monaco', 'Menlo', monospace;
font-size: 12px;
line-height: 1.6;
margin: 0; padding: 12px 14px; overflow-x: auto;
font-size: 11px; line-height: 1.5;
}
.step-code code { color: var(--vp-c-text-2); font-family: var(--vp-font-family-mono); }
.arrow { text-align: center; padding: 8px; color: var(--vp-c-text-3); font-size: 12px; }
.code-line {
padding: 2px 0;
}
.comment {
color: #6a9955;
}
.keyword {
color: #569cd6;
}
.highlight {
background: #fff3cd;
padding: 2px 4px;
border-radius: 3px;
color: #856404;
}
.string {
color: #ce9178;
}
.flow-arrow {
text-align: center;
padding: 12px;
color: #909399;
font-size: 13px;
font-weight: 500;
}
.dto-comparison {
background: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
}
.dto-comparison h5 {
margin: 0 0 16px 0;
color: #1a1a2e;
font-size: 15px;
text-align: center;
}
.comparison-table {
overflow-x: auto;
}
.table-header, .table-row {
display: grid;
grid-template-columns: 100px 150px 1fr 120px;
gap: 12px;
padding: 12px;
align-items: center;
}
.table-header {
background: #f5f7fa;
border-radius: 6px;
font-weight: 600;
color: #303133;
font-size: 13px;
}
.table-row {
border-bottom: 1px solid #ebeef5;
font-size: 12px;
color: #606266;
}
.table-row:last-child {
border-bottom: none;
}
.layer-tag {
padding: 4px 10px;
border-radius: 12px;
font-size: 11px;
font-weight: 500;
display: inline-block;
}
.layer-tag.controller {
background: #f0f9ff;
color: #1890ff;
}
.layer-tag.service {
background: #fff7e6;
color: #fa8c16;
}
.layer-tag.repository {
background: #f6ffed;
color: #52c41a;
}
@media (max-width: 768px) {
.table-header, .table-row {
grid-template-columns: 1fr;
gap: 8px;
}
.table-header {
display: none;
}
.table-box {
padding: 16px; border-radius: 10px;
background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider);
}
.table-title { text-align: center; font-weight: 600; font-size: 14px; color: var(--vp-c-text-1); margin-bottom: 12px; }
table { width: 100%; border-collapse: collapse; font-size: 12px; }
th, td { padding: 10px; text-align: left; border-bottom: 1px solid var(--vp-c-divider); color: var(--vp-c-text-2); }
th { background: var(--vp-c-bg-soft); font-weight: 600; color: var(--vp-c-text-1); }
.tag { padding: 2px 8px; border-radius: 10px; font-size: 11px; color: #fff; }
.tag.green { background: #10b981; }
.tag.orange { background: #f59e0b; }
.tag.blue { background: #3b82f6; }
</style>