feat: Spring Boot 学习脚手架 v2.0
- 新增 IoC 容器学习模块 - 新增 AOP 切面编程学习模块 - 新增 MyBatis 集成学习模块 - 新增事务管理学习模块 - 新增用户/产品/订单 CRUD - 新增 7 个交互式学习页面 - 集成性能监控切面
This commit is contained in:
175
target/classes/static/ioc.html
Normal file
175
target/classes/static/ioc.html
Normal file
@@ -0,0 +1,175 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>IoC 容器学习 - 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, #667eea 0%, #764ba2 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: #667eea; 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: #667eea; margin-bottom: 15px; border-bottom: 2px solid #eee; padding-bottom: 10px; }
|
||||
|
||||
.concept-box { background: #f8f9fa; border-left: 4px solid #667eea; padding: 15px; margin: 10px 0; border-radius: 5px; }
|
||||
.concept-box h4 { color: #333; margin-bottom: 10px; }
|
||||
|
||||
.btn { padding: 10px 20px; background: #667eea; color: white; border: none; border-radius: 5px; cursor: pointer; margin: 5px; }
|
||||
.btn:hover { background: #5a6fd6; }
|
||||
.btn-secondary { background: #6c757d; }
|
||||
|
||||
.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; }
|
||||
|
||||
table { width: 100%; border-collapse: collapse; margin: 10px 0; }
|
||||
th, td { padding: 10px; text-align: left; border-bottom: 1px solid #eee; }
|
||||
th { background: #f8f9fa; font-weight: 600; }
|
||||
tr:hover { background: #f8f9fa; }
|
||||
|
||||
.badge { padding: 4px 8px; border-radius: 4px; font-size: 0.8em; }
|
||||
.badge-primary { background: #667eea; color: white; }
|
||||
.badge-success { background: #28a745; color: white; }
|
||||
.badge-warning { background: #ffc107; color: #333; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>📦 IoC 容器学习</h1>
|
||||
<p>控制反转 (Inversion of Control) 与依赖注入 (Dependency Injection)</p>
|
||||
</div>
|
||||
|
||||
<div class="nav">
|
||||
<a href="index.html">🏠 首页</a>
|
||||
<a href="ioc.html" class="active">📦 IoC</a>
|
||||
<a href="aop.html">🔪 AOP</a>
|
||||
<a href="mybatis.html">💾 MyBatis</a>
|
||||
<a href="transaction.html">🔄 事务</a>
|
||||
<a href="users.html">👥 用户</a>
|
||||
<a href="api.html">🔌 API</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>📚 核心概念</h3>
|
||||
<div class="concept-box">
|
||||
<h4>什么是 IoC?</h4>
|
||||
<p><strong>控制反转 (Inversion of Control)</strong>:将对象的创建和管理交给 Spring 容器,而不是由开发者手动创建。</p>
|
||||
<p><strong>依赖注入 (Dependency Injection)</strong>:IoC 的一种实现方式,通过构造器、Setter 或字段将依赖注入到对象中。</p>
|
||||
</div>
|
||||
<div class="concept-box">
|
||||
<h4>为什么用 IoC?</h4>
|
||||
<ul>
|
||||
<li>✅ <strong>解耦</strong>:对象之间不直接依赖,通过接口交互</li>
|
||||
<li>✅ <strong>可测试</strong>:方便使用 Mock 对象进行单元测试</li>
|
||||
<li>✅ <strong>可维护</strong>:集中管理对象生命周期</li>
|
||||
<li>✅ <strong>AOP 支持</strong>:便于实现切面编程</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>🔍 查看所有 Bean</h3>
|
||||
<p>Spring 容器中管理的所有 Bean 对象</p>
|
||||
<button class="btn" onclick="loadBeans()">刷新 Bean 列表</button>
|
||||
<button class="btn btn-secondary" onclick="document.getElementById('beansResult').innerHTML=''">清空</button>
|
||||
<div id="beansResult" class="result"></div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>📊 Bean 作用域</h3>
|
||||
<table>
|
||||
<tr><th>作用域</th><th>说明</th><th>使用场景</th></tr>
|
||||
<tr><td><span class="badge badge-primary">singleton</span></td><td>默认,整个应用只有一个实例</td><td>无状态的服务、配置类</td></tr>
|
||||
<tr><td><span class="badge badge-success">prototype</span></td><td>每次请求都创建新实例</td><td>有状态的对象</td></tr>
|
||||
<tr><td><span class="badge badge-warning">request</span></td><td>每个 HTTP 请求一个实例</td><td>Web 应用</td></tr>
|
||||
<tr><td><span class="badge badge-warning">session</span></td><td>每个 HTTP 会话一个实例</td><td>用户会话数据</td></tr>
|
||||
</table>
|
||||
<button class="btn" onclick="testScopes()">测试作用域</button>
|
||||
<div id="scopesResult" class="result"></div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>⚡ 性能统计</h3>
|
||||
<p>实时监控方法执行时间和调用次数</p>
|
||||
<button class="btn" onclick="loadPerformance()">刷新统计</button>
|
||||
<button class="btn btn-secondary" onclick="resetPerformance()">重置统计</button>
|
||||
<div id="performanceResult" class="result"></div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>💉 依赖注入方式对比</h3>
|
||||
<table>
|
||||
<tr><th>方式</th><th>优点</th><th>缺点</th><th>推荐度</th></tr>
|
||||
<tr><td>构造器注入</td><td>明确依赖、不可变、易测试</td><td>参数多时代码长</td><td>⭐⭐⭐⭐⭐</td></tr>
|
||||
<tr><td>Setter 注入</td><td>可选依赖、灵活</td><td>可能为 null</td><td>⭐⭐⭐</td></tr>
|
||||
<tr><td>字段注入</td><td>代码简洁</td><td>隐藏依赖、难测试</td><td>⭐</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function loadBeans() {
|
||||
const result = document.getElementById('beansResult');
|
||||
result.textContent = '加载中...';
|
||||
try {
|
||||
const res = await fetch('/api/learning/ioc/beans');
|
||||
const data = await res.json();
|
||||
result.innerHTML = `<strong>总 Bean 数: ${data.total}</strong>\n\n用户相关 Bean:\n${data.userBeans.map(b => ' - ' + b).join('\n')}`;
|
||||
} catch (e) {
|
||||
result.textContent = '加载失败: ' + e.message;
|
||||
}
|
||||
}
|
||||
|
||||
async function testScopes() {
|
||||
const result = document.getElementById('scopesResult');
|
||||
try {
|
||||
const res = await fetch('/api/learning/ioc/scopes');
|
||||
const data = await res.json();
|
||||
result.innerHTML = JSON.stringify(data, null, 2);
|
||||
} catch (e) {
|
||||
result.textContent = '测试失败: ' + e.message;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadPerformance() {
|
||||
const result = document.getElementById('performanceResult');
|
||||
result.textContent = '加载中...';
|
||||
try {
|
||||
const res = await fetch('/api/learning/ioc/performance');
|
||||
const data = await res.json();
|
||||
if (Object.keys(data).length === 0) {
|
||||
result.textContent = '暂无性能数据,请先调用一些 API';
|
||||
return;
|
||||
}
|
||||
let html = '<table><tr><th>方法</th><th>调用次数</th><th>错误数</th><th>平均耗时(ms)</th><th>最大耗时(ms)</th></tr>';
|
||||
for (const [key, val] of Object.entries(data)) {
|
||||
html += `<tr><td>${key}</td><td>${val.count}</td><td>${val.errors}</td><td>${val.avgMs}</td><td>${val.maxMs}</td></tr>`;
|
||||
}
|
||||
html += '</table>';
|
||||
result.innerHTML = html;
|
||||
} catch (e) {
|
||||
result.textContent = '加载失败: ' + e.message;
|
||||
}
|
||||
}
|
||||
|
||||
async function resetPerformance() {
|
||||
try {
|
||||
await fetch('/api/learning/ioc/performance/reset', { method: 'POST' });
|
||||
loadPerformance();
|
||||
} catch (e) {
|
||||
alert('重置失败: ' + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
loadBeans();
|
||||
loadPerformance();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user