feat(v1): add learn/advanced profiles and interactive learning task card

This commit is contained in:
likingcode
2026-03-08 14:40:30 +00:00
parent dd2b4d0e4b
commit 2b8b4213e2
5 changed files with 131 additions and 3 deletions

View File

@@ -0,0 +1,46 @@
# 高级配置 - 可插拔组件
spring:
config:
activate:
on-profile: advanced
# 数据库选择: h2 / mysql / postgresql
datasource:
driver-class-name: ${DB_DRIVER:org.h2.Driver}
url: ${DB_URL:jdbc:h2:file:~/h2/springboot_scaffold}
username: ${DB_USER:sa}
password: ${DB_PASS:}
# Redis 缓存
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASS:}
database: ${REDIS_DB:0}
timeout: 3000ms
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
# 鉴权方案选择: none / jwt / satoken
auth:
type: ${AUTH_TYPE:none} # none | jwt | satoken
jwt:
secret: ${JWT_SECRET:your-secret-key}
expiration: ${JWT_EXPIRATION:86400000} # 24小时
satoken:
timeout: ${SA_TIMEOUT:86400} # 24小时
activity-timeout: ${SA_ACTIVITY_TIMEOUT:1800} # 30分钟
# 缓存配置
cache:
type: ${CACHE_TYPE:caffeine} # caffeine | redis
redis:
time-to-live: 600000 # 10分钟
# MyBatis 多数据库适配
mybatis:
configuration:
database-id: ${DB_TYPE:h2} # h2 | mysql | postgresql

View File

@@ -0,0 +1,20 @@
# Learn profile: keep dependencies and runtime simple for first-round learning
spring:
config:
activate:
on-profile: learn
app:
profile: learn
enabled-modules:
- ioc
- aop
- mybatis
- transaction
- users
auth:
type: none
cache:
type: caffeine

View File

@@ -1,7 +1,9 @@
spring.application.name=springboot-scaffold
server.port=8082
# H2 Database
spring.profiles.active=${APP_PROFILE:learn}
# H2 Database (default for learning)
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:file:~/h2/springboot_scaffold
spring.datasource.driverClassName=org.h2.Driver

View File

@@ -41,6 +41,9 @@
.status-item { background: white; padding: 20px 30px; border-radius: 10px; text-align: center; }
.status-item .value { font-size: 2em; font-weight: bold; color: #667eea; }
.status-item .label { color: #666; margin-top: 5px; }
.lab { background:#fff7e6; border:1px solid #ffe58f; border-radius:10px; padding:16px; margin-bottom:20px; }
.lab h4 { margin-bottom:8px; color:#ad6800; }
.lab ul { margin-left:18px; color:#444; line-height:1.7; }
footer { text-align: center; padding: 30px; color: #666; margin-top: 40px; }
</style>
@@ -69,6 +72,21 @@
<div class="value" id="orderCount">-</div>
<div class="label">订单数量</div>
</div>
<div class="status-item">
<div class="value" id="activeProfile">-</div>
<div class="label">当前 Profile</div>
</div>
</div>
<div class="lab">
<h4>🧪 实验任务卡(事务模块)</h4>
<ul>
<li>目标:理解事务回滚与 REQUIRES_NEW 差异</li>
<li>步骤1到 transaction.html 创建普通订单rollback=false</li>
<li>步骤2再创建模拟失败订单rollback=true</li>
<li>预期:主事务回滚,但独立事务可保留日志/部分数据(取决于实现)</li>
<li>观察点查看控制台事务日志TransactionInterceptor TRACE</li>
</ul>
</div>
<div class="nav">
@@ -78,6 +96,7 @@
<a href="mybatis.html">💾 MyBatis</a>
<a href="transaction.html">🔄 事务管理</a>
<a href="users.html">👥 用户管理</a>
<a href="advanced.html">🚀 高级功能</a>
<a href="api.html">🔌 API 测试</a>
</div>
@@ -142,6 +161,19 @@
<a href="users.html" class="btn">开始学习 →</a>
</div>
<div class="card">
<h3>🚀 高级功能</h3>
<p>Redis 缓存、分布式锁、多数据库、认证方案对比,从小白到高手的进阶之路。</p>
<ul class="feature-list">
<li><span class="icon"></span>Redis 数据类型操作</li>
<li><span class="icon"></span>缓存穿透/击穿/雪崩</li>
<li><span class="icon"></span>分布式锁实现</li>
<li><span class="icon"></span>JWT vs Sa-Token</li>
<li><span class="icon"></span>多数据库切换</li>
</ul>
<a href="advanced.html" class="btn">进阶学习 →</a>
</div>
<div class="card">
<h3>🔌 API 测试面板</h3>
<p>在线测试所有 API 接口,查看请求响应,理解 RESTful API 工作原理。</p>
@@ -180,17 +212,19 @@
// 加载状态数据
async function loadStatus() {
try {
const [beans, users, products, orders] = await Promise.all([
const [beans, users, products, orders, profile] = await Promise.all([
fetch('/api/learning/ioc/beans').then(r => r.json()),
fetch('/api/users/count').then(r => r.json()),
fetch('/api/products').then(r => r.json()),
fetch('/api/orders').then(r => r.json())
fetch('/api/orders').then(r => r.json()),
fetch('/api/profile').then(r => r.json())
]);
document.getElementById('beanCount').textContent = beans.total || '-';
document.getElementById('userCount').textContent = users.count || 0;
document.getElementById('productCount').textContent = products.length || 0;
document.getElementById('orderCount').textContent = orders.length || 0;
document.getElementById('activeProfile').textContent = profile.profile || '-';
} catch (e) {
console.error('加载状态失败:', e);
}