feat: Spring Boot 学习脚手架 v2.0

- 新增 IoC 容器学习模块
- 新增 AOP 切面编程学习模块
- 新增 MyBatis 集成学习模块
- 新增事务管理学习模块
- 新增用户/产品/订单 CRUD
- 新增 7 个交互式学习页面
- 集成性能监控切面
This commit is contained in:
likingcode
2026-03-07 08:37:40 +00:00
commit c04235c655
73 changed files with 4978 additions and 0 deletions

View File

@@ -0,0 +1,176 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MyBatis 学习 - Spring Boot</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; }
.container { max-width: 1400px; margin: 0 auto; padding: 20px; }
.header { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); color: white; padding: 30px 20px; text-align: center; margin-bottom: 20px; border-radius: 10px; }
.header h1 { font-size: 2em; }
.nav { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; justify-content: center; }
.nav a { padding: 10px 20px; background: white; border-radius: 20px; text-decoration: none; color: #333; font-size: 0.9em; }
.nav a:hover, .nav a.active { background: #4facfe; color: white; }
.card { background: white; border-radius: 10px; padding: 20px; margin-bottom: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.08); }
.card h3 { color: #4facfe; margin-bottom: 15px; border-bottom: 2px solid #eee; padding-bottom: 10px; }
.comparison { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.compare-box { padding: 20px; border-radius: 10px; }
.mybatis-box { background: #e3f2fd; border: 2px solid #4facfe; }
.jpa-box { background: #f3e5f5; border: 2px solid #9c27b0; }
.btn { padding: 10px 20px; background: #4facfe; color: white; border: none; border-radius: 5px; cursor: pointer; margin: 5px; }
.btn:hover { background: #3d9be8; }
.result { background: #1e1e1e; color: #d4d4d4; padding: 15px; border-radius: 5px; margin-top: 10px; font-family: monospace; font-size: 0.9em; overflow-x: auto; max-height: 400px; overflow-y: auto; }
.code-block { background: #f4f4f4; padding: 15px; border-radius: 5px; font-family: monospace; font-size: 0.9em; overflow-x: auto; margin: 10px 0; }
.cache-box { background: #fff3e0; border-left: 4px solid #ff9800; padding: 15px; margin: 10px 0; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>💾 MyBatis 学习</h1>
<p>半自动 ORM 框架 - SQL 与 Java 对象的映射</p>
</div>
<div class="nav">
<a href="index.html">🏠 首页</a>
<a href="ioc.html">📦 IoC</a>
<a href="aop.html">🔪 AOP</a>
<a href="mybatis.html" class="active">💾 MyBatis</a>
<a href="transaction.html">🔄 事务</a>
<a href="users.html">👥 用户</a>
<a href="api.html">🔌 API</a>
</div>
<div class="card">
<h3>📊 MyBatis vs JPA 对比</h3>
<div class="comparison">
<div class="compare-box mybatis-box">
<h4>MyBatis</h4>
<p><strong>优点:</strong></p>
<ul>
<li>✅ SQL 灵活可控</li>
<li>✅ 性能优化方便</li>
<li>✅ 复杂查询友好</li>
<li>✅ 易于 DBA 协作</li>
</ul>
<p><strong>缺点:</strong></p>
<ul>
<li>❌ SQL 与代码耦合</li>
<li>❌ 数据库迁移成本高</li>
<li>❌ 需要手写 SQL</li>
</ul>
<p><strong>适用:</strong>复杂查询、性能要求高</p>
</div>
<div class="compare-box jpa-box">
<h4>JPA/Hibernate</h4>
<p><strong>优点:</strong></p>
<ul>
<li>✅ 面向对象</li>
<li>✅ 数据库无关</li>
<li>✅ 开发效率高</li>
<li>✅ 自动维护</li>
</ul>
<p><strong>缺点:</strong></p>
<ul>
<li>❌ 复杂查询困难</li>
<li>❌ 性能调优复杂</li>
<li>❌ 学习曲线陡</li>
</ul>
<p><strong>适用:</strong>标准 CRUD、快速开发</p>
</div>
</div>
</div>
<div class="card">
<h3>🚀 快速体验</h3>
<button class="btn" onclick="loadConfig()">查看 MyBatis 配置</button>
<button class="btn" onclick="loadConcepts()">核心概念</button>
<button class="btn" onclick="loadVsJpa()">详细对比</button>
<div id="result" class="result"></div>
</div>
<div class="card">
<h3>💡 缓存机制</h3>
<div class="cache-box">
<h4>一级缓存 (SqlSession 级别)</h4>
<p>默认开启,同一 SqlSession 内相同查询只执行一次 SQL</p>
<div class="code-block">// 第一次查询 - 执行 SQL<br>User u1 = mapper.findById(1L);<br>// 第二次查询 - 命中缓存,不执行 SQL<br>User u2 = mapper.findById(1L);</div>
</div>
<div class="cache-box">
<h4>二级缓存 (Mapper 级别)</h4>
<p>需配置 @CacheNamespace多个 SqlSession 共享</p>
<div class="code-block">@Mapper<br>@CacheNamespace<br>public interface UserMapper { ... }</div>
</div>
<p>💡 <strong>验证方式:</strong>查看控制台 SQL 日志,缓存命中时不打印 SQL</p>
</div>
<div class="card">
<h3>📝 常用注解</h3>
<table style="width:100%;border-collapse:collapse;">
<tr style="background:#f8f9fa;"><th style="padding:10px;text-align:left;">注解</th><th style="padding:10px;text-align:left;">用途</th></tr>
<tr><td style="padding:10px;border-bottom:1px solid #eee;">@Mapper</td><td style="padding:10px;border-bottom:1px solid #eee;">标记为 MyBatis Mapper 接口</td></tr>
<tr><td style="padding:10px;border-bottom:1px solid #eee;">@Select</td><td style="padding:10px;border-bottom:1px solid #eee;">查询 SQL</td></tr>
<tr><td style="padding:10px;border-bottom:1px solid #eee;">@Insert</td><td style="padding:10px;border-bottom:1px solid #eee;">插入 SQL</td></tr>
<tr><td style="padding:10px;border-bottom:1px solid #eee;">@Update</td><td style="padding:10px;border-bottom:1px solid #eee;">更新 SQL</td></tr>
<tr><td style="padding:10px;border-bottom:1px solid #eee;">@Delete</td><td style="padding:10px;border-bottom:1px solid #eee;">删除 SQL</td></tr>
<tr><td style="padding:10px;border-bottom:1px solid #eee;">@Param</td><td style="padding:10px;border-bottom:1px solid #eee;">参数命名</td></tr>
<tr><td style="padding:10px;border-bottom:1px solid #eee;">@Options</td><td style="padding:10px;border-bottom:1px solid #eee;">额外选项如返回自增ID</td></tr>
<tr><td style="padding:10px;border-bottom:1px solid #eee;">@CacheNamespace</td><td style="padding:10px;border-bottom:1px solid #eee;">启用二级缓存</td></tr>
</table>
</div>
<div class="card">
<h3>🔧 动态 SQL 示例</h3>
<div class="code-block">&lt;select id="findUsers"&gt;<br> SELECT * FROM users<br> &lt;where&gt;<br> &lt;if test="name != null"&gt;<br> AND name LIKE CONCAT('%', #{name}, '%')<br> &lt;/if&gt;<br> &lt;if test="email != null"&gt;<br> AND email = #{email}<br> &lt;/if&gt;<br> &lt;/where&gt;<br>&lt;/select&gt;</div>
</div>
</div>
<script>
async function loadConfig() {
const result = document.getElementById('result');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/mybatis/config');
const data = await res.json();
result.innerHTML = `<strong>MyBatis 配置</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
async function loadConcepts() {
const result = document.getElementById('result');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/mybatis/concepts');
const data = await res.json();
result.innerHTML = `<strong>核心概念</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
async function loadVsJpa() {
const result = document.getElementById('result');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/mybatis/vs-jpa');
const data = await res.json();
result.innerHTML = `<strong>MyBatis vs JPA</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
</script>
</body>
</html>