Update: cache module, security modules and build
This commit is contained in:
260
target/classes/static/advanced.html
Normal file
260
target/classes/static/advanced.html
Normal file
@@ -0,0 +1,260 @@
|
||||
<!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>
|
||||
Reference in New Issue
Block a user