Files
2026-03-18 15:18:41 +08:00

260 lines
13 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>高级功能学习 - 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, #f093fb 0%, #f5576c 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: #f5576c; 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: #f5576c; margin-bottom: 15px; border-bottom: 2px solid #eee; padding-bottom: 10px; }
.config-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 15px; }
.config-item { background: #f8f9fa; padding: 15px; border-radius: 8px; border-left: 4px solid #f5576c; }
.config-item h4 { margin-bottom: 10px; }
.config-item .current { color: #28a745; font-weight: bold; }
.btn { padding: 10px 20px; background: #f5576c; color: white; border: none; border-radius: 5px; cursor: pointer; margin: 5px; }
.btn:hover { background: #e0465b; }
.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; }
.compare-table { width: 100%; border-collapse: collapse; margin: 15px 0; }
.compare-table th, .compare-table td { padding: 12px; text-align: left; border-bottom: 1px solid #eee; }
.compare-table th { background: #f8f9fa; }
.compare-table tr:hover { background: #f8f9fa; }
.problem-box { background: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; margin: 10px 0; border-radius: 5px; }
.problem-box h4 { color: #856404; margin-bottom: 8px; }
.redis-types { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 10px; }
.redis-type { background: #e3f2fd; padding: 15px; border-radius: 8px; }
.redis-type h4 { color: #1976d2; margin-bottom: 5px; }
.tipbox { background:#fff7e6;border-left:4px solid #fa8c16;padding:15px;border-radius:8px;margin-bottom:20px; }
.tipbox h4 { color:#ad6800;margin-bottom:8px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🚀 高级功能学习</h1>
<p>Redis 缓存 | 分布式锁 | 多数据库 | 认证方案</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">💾 MyBatis</a>
<a href="transaction.html">🔄 事务</a>
<a href="users.html">👥 用户</a>
<a href="advanced.html" class="active">🚀 高级</a>
<a href="auth-lab.html">🔐 鉴权实验室</a>
<a href="api.html">🔌 API</a>
</div>
<div class="tipbox">
<h4>🧪 实验任务卡(高级模块)</h4>
<label style="display:block;margin-bottom:8px;"><input id="advancedTaskDone" type="checkbox" onchange="toggleAdvancedTaskDone(this)"> 本任务我已经完成</label>
<ul style="padding-left:20px;line-height:1.8;">
<li>目标:比较 learn/advanced profile 下可用能力差异</li>
<li>步骤1先查看“系统配置”和“认证方案对比”</li>
<li>步骤2执行 Redis SET/GET + 分布式锁接口</li>
<li>预期advanced 模式下功能更完整,返回字段更丰富</li>
<li>常见坑:本机无 Redis 导致接口失败(属于环境问题)</li>
</ul>
</div>
<div class="card">
<h3>⚙️ 系统配置</h3>
<button class="btn" onclick="loadConfig()">查看当前配置</button>
<div id="configResult" class="result"></div>
</div>
<div class="card">
<h3>🔐 认证方案对比</h3>
<button class="btn" onclick="loadAuthCompare()">JWT vs Sa-Token</button>
<a class="btn btn-secondary" href="auth-lab.html">进入鉴权实验室</a>
<div id="authResult" class="result"></div>
</div>
<div class="card">
<h3>💾 Redis 数据类型</h3>
<div class="redis-types">
<div class="redis-type"><h4>String</h4><p>字符串,最基本类型</p></div>
<div class="redis-type"><h4>Hash</h4><p>哈希,存储对象</p></div>
<div class="redis-type"><h4>List</h4><p>列表,队列/栈</p></div>
<div class="redis-type"><h4>Set</h4><p>集合,去重运算</p></div>
<div class="redis-type"><h4>SortedSet</h4><p>有序集合,排名</p></div>
</div>
<button class="btn" onclick="loadRedisTypes()">查看详细说明</button>
</div>
<div class="card">
<h3>🧪 Redis 操作测试</h3>
<div style="display:flex;gap:10px;margin-bottom:15px;">
<input type="text" id="redisKey" placeholder="Key" style="flex:1;padding:10px;border:1px solid #ddd;border-radius:5px;">
<input type="text" id="redisValue" placeholder="Value" style="flex:1;padding:10px;border:1px solid #ddd;border-radius:5px;">
<input type="number" id="redisTtl" placeholder="TTL(秒)" value="60" style="width:100px;padding:10px;border:1px solid #ddd;border-radius:5px;">
</div>
<button class="btn" onclick="setRedisString()">SET</button>
<button class="btn btn-secondary" onclick="getRedisString()">GET</button>
<div id="redisResult" class="result"></div>
</div>
<div class="card">
<h3>🔒 分布式锁演示</h3>
<p>模拟多个请求竞争同一资源</p>
<input type="text" id="lockResource" placeholder="资源名称" value="order:1001" style="padding:10px;border:1px solid #ddd;border-radius:5px;margin-right:10px;">
<button class="btn" onclick="testDistributedLock()">获取分布式锁</button>
<div id="lockResult" class="result"></div>
</div>
<div class="card">
<h3>⚠️ 缓存三大问题</h3>
<div class="problem-box">
<h4>缓存穿透</h4>
<p><strong>问题:</strong>查询不存在的数据,每次都打到数据库</p>
<p><strong>解决:</strong>布隆过滤器 | 缓存空值</p>
</div>
<div class="problem-box">
<h4>缓存击穿</h4>
<p><strong>问题:</strong>热点key过期大量请求打到数据库</p>
<p><strong>解决:</strong>互斥锁 | 逻辑过期</p>
</div>
<div class="problem-box">
<h4>缓存雪崩</h4>
<p><strong>问题:</strong>大量key同时过期数据库压力激增</p>
<p><strong>解决:</strong>随机过期时间 | 多级缓存</p>
</div>
<button class="btn" onclick="loadCacheProblems()">查看详细方案</button>
<div id="cacheResult" class="result"></div>
</div>
</div>
<script>
const ADV_TASK_KEY = 'task.advanced.done';
function toggleAdvancedTaskDone(el) {
localStorage.setItem(ADV_TASK_KEY, el.checked ? '1' : '0');
}
function initAdvancedTaskState() {
const done = localStorage.getItem(ADV_TASK_KEY) === '1';
const checkbox = document.getElementById('advancedTaskDone');
if (checkbox) checkbox.checked = done;
}
async function loadConfig() {
const result = document.getElementById('configResult');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/advanced/config');
const data = await res.json();
result.innerHTML = `<strong>系统配置</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
async function loadAuthCompare() {
const result = document.getElementById('authResult');
result.textContent = '加载中...';
try {
const res = await fetch('/api/learning/advanced/auth/compare');
const data = await res.json();
result.innerHTML = `<strong>认证方案对比</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
async function loadRedisTypes() {
const result = document.getElementById('redisResult');
try {
const res = await fetch('/api/learning/advanced/redis/types');
const data = await res.json();
result.innerHTML = `<strong>Redis 数据类型</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
async function setRedisString() {
const key = document.getElementById('redisKey').value;
const value = document.getElementById('redisValue').value;
const ttl = document.getElementById('redisTtl').value;
if (!key || !value) {
alert('请输入 Key 和 Value');
return;
}
const result = document.getElementById('redisResult');
try {
const res = await fetch(`/api/learning/advanced/redis/string?key=${encodeURIComponent(key)}&value=${encodeURIComponent(value)}&ttl=${ttl}`, { method: 'POST' });
const data = await res.json();
result.innerHTML = `<strong>SET 结果</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '操作失败: ' + e.message;
}
}
async function getRedisString() {
const key = document.getElementById('redisKey').value;
if (!key) {
alert('请输入 Key');
return;
}
const result = document.getElementById('redisResult');
try {
const res = await fetch(`/api/learning/advanced/redis/string?key=${encodeURIComponent(key)}`);
const data = await res.json();
result.innerHTML = `<strong>GET 结果</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '操作失败: ' + e.message;
}
}
async function testDistributedLock() {
const resource = document.getElementById('lockResource').value;
const result = document.getElementById('lockResult');
result.textContent = '获取锁中...';
try {
const res = await fetch(`/api/learning/advanced/redis/lock?resource=${encodeURIComponent(resource)}`, { method: 'POST' });
const data = await res.json();
result.innerHTML = `<strong>分布式锁结果</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '操作失败: ' + e.message;
}
}
async function loadCacheProblems() {
const result = document.getElementById('cacheResult');
try {
const res = await fetch('/api/learning/advanced/cache/problems');
const data = await res.json();
result.innerHTML = `<strong>缓存问题解决方案</strong>\n\n${JSON.stringify(data, null, 2)}`;
} catch (e) {
result.textContent = '加载失败: ' + e.message;
}
}
loadConfig();
initAdvancedTaskState();
</script>
</body>
</html>