fdwei4 commited on
Commit
8dc6765
·
1 Parent(s): b9a530a

feat: 首页改为可交互的 Demo CRUD 表格

Browse files
src/main/java/com/example/hfspace/controller/HelloController.java CHANGED
@@ -7,67 +7,148 @@ import org.springframework.web.bind.annotation.GetMapping;
7
  import org.springframework.web.bind.annotation.RestController;
8
 
9
  /**
10
- * 演示接口:一个首页 HTML 和一个 JSON 接口,用于验证服务已上线。
11
  */
12
  @RestController
13
  public class HelloController {
14
 
15
- /** 首页:返回一段 HTML。 */
16
  @GetMapping(value = "/", produces = "text/html;charset=UTF-8")
17
  public String home() {
18
  return """
19
- <html>
20
- <head><meta charset="utf-8"><title>HF Space Demo</title></head>
21
- <body style="font-family: sans-serif; padding: 40px; max-width: 800px; margin: 0 auto;">
22
- <h1>🚀 HF Space Spring Boot Demo</h1>
23
- <p>部署成功!基于 <strong>wfly-spring</strong> 配置(SQLPub MySQL + Upstash Redis)。</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
- <h2>📡 接口列表</h2>
26
- <ul>
27
- <li><strong>基础接口</strong>
28
- <ul>
29
- <li><a href="/api/hello">/api/hello</a> - 返回 JSON</li>
30
- </ul>
31
- </li>
32
- <li><strong>MySQL 示例</strong>(Demo CRUD,MyBatis Plus)
33
- <ul>
34
- <li><code>GET</code> <a href="/api/demo">/api/demo</a> - 列出所有项</li>
35
- <li><code>POST /api/demo</code> - 创建(Body: <code>{"title":"Test","content":"Hello"}</code>)</li>
36
- <li><code>GET /api/demo/{id}</code> - 查询单个</li>
37
- <li><code>PUT /api/demo/{id}</code> - 更新</li>
38
- <li><code>DELETE /api/demo/{id}</code> - 删除(逻辑删除)</li>
39
- </ul>
40
- </li>
41
- <li><strong>Redis 示例</strong>(Upstash 缓存)
42
- <ul>
43
- <li><a href="/api/cache/health">/api/cache/health</a> - Redis 健康检查</li>
44
- <li><code>POST /api/cache</code> - 存缓存(Body: <code>{"key":"foo","value":"bar","ttl":60}</code>)</li>
45
- <li><code>GET /api/cache/{key}</code> - 读缓存</li>
46
- <li><code>DELETE /api/cache/{key}</code> - 删缓存</li>
47
- </ul>
48
- </li>
49
- <li><strong>Druid 监控</strong>
50
- <ul>
51
- <li><a href="/druid/">/druid/</a> - 数据库连接池监控(用户名: admin / 密码: admin123)</li>
52
- </ul>
53
- </li>
54
- </ul>
55
 
56
- <h2>📚 文档</h2>
 
57
  <ul>
58
- <li><a href="https://github.com/yourusername/yourrepo/blob/main/README.md">README.md</a> - 快速入门</li>
59
- <li><a href="https://github.com/yourusername/yourrepo/blob/main/ARCHITECTURE.md">ARCHITECTURE.md</a> - 架构详解</li>
60
- <li><a href="https://github.com/yourusername/yourrepo/blob/main/DEPLOY.md">DEPLOY.md</a> - 部署清单</li>
61
  </ul>
 
62
 
63
- <h2>✅ 凭据来源</h2>
64
- <p>此 demo 直接复用 <code>wfly-spring/application-dev.yaml</code> 的真实配置:</p>
65
- <ul>
66
- <li><strong>MySQL</strong>: <code>mysql6.sqlpub.com:3311/vftdream</code>(master)</li>
67
- <li><strong>Redis</strong>: <code>hot-boa-127738.upstash.io</code>(Upstash 主库)</li>
68
- </ul>
69
- <p>⚠️ <strong>注意</strong>:示例数据会写入真实数据库,生产环境请单独配置。</p>
70
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  </html>
72
  """;
73
  }
 
7
  import org.springframework.web.bind.annotation.RestController;
8
 
9
  /**
10
+ * 演示接口:一个首页 HTML(含 Demo 数据 CRUD 表格)和一个 JSON 接口。
11
  */
12
  @RestController
13
  public class HelloController {
14
 
15
+ /** 首页:返回一段带 CRUD 表格的 HTML,直接对接 /api/demo 接口。 */
16
  @GetMapping(value = "/", produces = "text/html;charset=UTF-8")
17
  public String home() {
18
  return """
19
+ <!DOCTYPE html>
20
+ <html lang="zh">
21
+ <head>
22
+ <meta charset="utf-8">
23
+ <meta name="viewport" content="width=device-width, initial-scale=1">
24
+ <title>HF Space Demo</title>
25
+ <style>
26
+ body { font-family: -apple-system, sans-serif; padding: 24px; max-width: 960px; margin: 0 auto; color: #1f2329; }
27
+ h1 { margin-bottom: 4px; }
28
+ .sub { color: #646a73; margin-top: 0; }
29
+ .card { border: 1px solid #e5e6eb; border-radius: 8px; padding: 16px; margin: 16px 0; }
30
+ .form-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
31
+ input { padding: 8px 10px; border: 1px solid #c9cdd4; border-radius: 6px; font-size: 14px; }
32
+ input#title { width: 180px; }
33
+ input#content { flex: 1; min-width: 200px; }
34
+ button { padding: 8px 14px; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; }
35
+ .btn-primary { background: #3370ff; color: #fff; }
36
+ .btn-ghost { background: #f2f3f5; color: #1f2329; }
37
+ .btn-danger { background: #f53f3f; color: #fff; }
38
+ .btn-sm { padding: 4px 10px; font-size: 13px; }
39
+ table { width: 100%; border-collapse: collapse; margin-top: 8px; }
40
+ th, td { text-align: left; padding: 8px 10px; border-bottom: 1px solid #f0f0f0; font-size: 14px; vertical-align: top; }
41
+ th { color: #646a73; font-weight: 500; background: #fafafa; }
42
+ td.actions { white-space: nowrap; }
43
+ .muted { color: #8a8f99; font-size: 12px; }
44
+ #msg { margin-left: 8px; font-size: 13px; }
45
+ .ok { color: #00b42a; }
46
+ .err { color: #f53f3f; }
47
+ a { color: #3370ff; }
48
+ </style>
49
+ </head>
50
+ <body>
51
+ <h1>🚀 HF Space Spring Boot Demo</h1>
52
+ <p class="sub">基于 wfly-spring 配置(SQLPub MySQL + Upstash Redis)。下表直接读写真实数据库 <code>demo_items</code> 表。</p>
53
 
54
+ <div class="card">
55
+ <h3 style="margin-top:0;">Demo 数据管理</h3>
56
+ <div class="form-row">
57
+ <input type="hidden" id="editId">
58
+ <input id="title" placeholder="标题 title">
59
+ <input id="content" placeholder="内容 content">
60
+ <button class="btn-primary" onclick="save()">保存</button>
61
+ <button class="btn-ghost" onclick="resetForm()">清空</button>
62
+ <button class="btn-ghost" onclick="load()">刷新</button>
63
+ <span id="msg"></span>
64
+ </div>
65
+ <table>
66
+ <thead>
67
+ <tr><th>ID</th><th>标题</th><th>内容</th><th>更新时间</th><th>操作</th></tr>
68
+ </thead>
69
+ <tbody id="rows"><tr><td colspan="5" class="muted">加载中…</td></tr></tbody>
70
+ </table>
71
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
+ <div class="card">
74
+ <h3 style="margin-top:0;">📡 其他接口</h3>
75
  <ul>
76
+ <li><a href="/api/hello">/api/hello</a> · <a href="/api/cache/health">/api/cache/health</a>(Redis) · <a href="/druid/">/druid/</a>(监控 admin/admin123)</li>
 
 
77
  </ul>
78
+ </div>
79
 
80
+ <script>
81
+ const API = '/api/demo';
82
+ const $ = id => document.getElementById(id);
83
+ function msg(text, ok) {
84
+ const m = $('msg');
85
+ m.textContent = text;
86
+ m.className = ok ? 'ok' : 'err';
87
+ setTimeout(() => { m.textContent = ''; }, 2500);
88
+ }
89
+ function esc(s) {
90
+ return String(s == null ? '' : s).replace(/[&<>"]/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]));
91
+ }
92
+ async function load() {
93
+ const tbody = $('rows');
94
+ try {
95
+ const res = await fetch(API);
96
+ const json = await res.json();
97
+ const list = json.data || [];
98
+ if (!list.length) { tbody.innerHTML = '<tr><td colspan="5" class="muted">暂无数据,添加一条试试</td></tr>'; return; }
99
+ tbody.innerHTML = list.map(it => `
100
+ <tr>
101
+ <td>${it.id}</td>
102
+ <td>${esc(it.title)}</td>
103
+ <td>${esc(it.content)}</td>
104
+ <td class="muted">${esc(it.updateTime || it.createTime || '')}</td>
105
+ <td class="actions">
106
+ <button class="btn-ghost btn-sm" onclick="edit(${it.id}, '${esc(it.title).replace(/'/g, "&#39;")}', '${esc(it.content).replace(/'/g, "&#39;")}')">编辑</button>
107
+ <button class="btn-danger btn-sm" onclick="del(${it.id})">删除</button>
108
+ </td>
109
+ </tr>`).join('');
110
+ } catch (e) {
111
+ tbody.innerHTML = '<tr><td colspan="5" class="err">加载失败:' + esc(e.message) + '</td></tr>';
112
+ }
113
+ }
114
+ async function save() {
115
+ const id = $('editId').value;
116
+ const title = $('title').value.trim();
117
+ const content = $('content').value.trim();
118
+ if (!title) { msg('标题不能为空', false); return; }
119
+ const body = JSON.stringify({ title, content });
120
+ const opts = { method: id ? 'PUT' : 'POST', headers: { 'Content-Type': 'application/json' }, body };
121
+ const url = id ? (API + '/' + id) : API;
122
+ try {
123
+ const res = await fetch(url, opts);
124
+ const json = await res.json();
125
+ if (json.code === 0) { msg(id ? '已更新' : '已创建', true); resetForm(); load(); }
126
+ else { msg(json.message || '操作失败', false); }
127
+ } catch (e) { msg('请求失败:' + e.message, false); }
128
+ }
129
+ function edit(id, title, content) {
130
+ $('editId').value = id;
131
+ $('title').value = title;
132
+ $('content').value = content;
133
+ $('title').focus();
134
+ }
135
+ function resetForm() {
136
+ $('editId').value = '';
137
+ $('title').value = '';
138
+ $('content').value = '';
139
+ }
140
+ async function del(id) {
141
+ if (!confirm('确定删除 #' + id + ' ?')) return;
142
+ try {
143
+ const res = await fetch(API + '/' + id, { method: 'DELETE' });
144
+ const json = await res.json();
145
+ if (json.code === 0) { msg('已删除', true); load(); }
146
+ else { msg(json.message || '删除失败', false); }
147
+ } catch (e) { msg('请求失败:' + e.message, false); }
148
+ }
149
+ load();
150
+ </script>
151
+ </body>
152
  </html>
153
  """;
154
  }