hono.js 使用mysql 查询博客文章上下文,并判断是否存在上下文,在jsx 模板中 显示博文,底部显示,上文,和下文链接。

以下是在 Hono.js 中结合 MySQL 查询和 JSX 模板实现博客文章上下文展示的完整示例:

// app.tsx
import { Hono } from 'hono'
import { jsx } from 'hono/jsx'
import { createPool } from 'mysql2/promise'

// 创建 MySQL 连接池
const pool = createPool({
  host: 'localhost',
  user: 'root',
  password: 'password',
  database: 'blog_db',
  waitForConnections: true,
  connectionLimit: 10,
})

const app = new Hono()

// 文章详情页路由
app.get('/post/:id', async (c) => {
  const id = c.req.param('id')

  try {
    // 获取当前文章
    const [currentPost] = await pool.query(
      'SELECT id, title, content FROM posts WHERE id = ?',
      [id]
    )

    if (!currentPost[0]) return c.notFound()

    // 获取上一篇(更早的文章)
    const [previousResult] = await pool.query(
      `SELECT id, title 
       FROM posts 
       WHERE publish_time < (SELECT publish_time FROM posts WHERE id = ?)
       ORDER BY publish_time DESC 
       LIMIT 1`,
      [id]
    )

    // 获取下一篇(更新的文章)
    const [nextResult] = await pool.query(
      `SELECT id, title 
       FROM posts 
       WHERE publish_time > (SELECT publish_time FROM posts WHERE id = ?)
       ORDER BY publish_time ASC 
       LIMIT 1`,
      [id]
    )

    const previousPost = previousResult[0] || null
    const nextPost = nextResult[0] || null

    return c.html(
      <PostPage 
        post={currentPost[0]} 
        previous={previousPost} 
        next={nextPost} 
      />
    )
  } catch (error) {
    console.error(error)
    return c.text('Internal Server Error', 500)
  }
})

// JSX 模板组件
const PostPage = ({ post, previous, next }) => (
  <html>
    <head>
      <title>{post.title}</title>
    </head>
    <body>
      <article>
        <h1>{post.title}</h1>
        <div>{post.content}</div>
      </article>

      <nav class="post-navigation">
        {/* 上一篇链接 */}
        {previous ? (
          <a href={`/post/${previous.id}`}>&laquo; {previous.title}</a>
        ) : (
          <span class="disabled">&laquo; 没有上一篇</span>
        )}

        {/* 下一篇链接 */}
        {next ? (
          <a href={`/post/${next.id}`} class="next">
            {next.title} &raquo;
          </a>
        ) : (
          <span class="disabled">没有下一篇 &raquo;</span>
        )}
      </nav>
    </body>
  </html>
)

export default app

关键实现说明:

  1. 数据库查询优化
// 使用子查询提高性能
const [previousResult] = await pool.query(
  `SELECT id, title 
   FROM posts 
   WHERE publish_time < (SELECT publish_time FROM current_post)
   ORDER BY publish_time DESC 
   LIMIT 1`
)
  1. 导航链接条件渲染
{/* 更安全的可选链判断 */}
{previous?.id && (
  <a href={`/post/${encodeURIComponent(previous.id)}`}>
    {previous.title}
  </a>
)}
  1. 样式增强方案
/* 添加 CSS 类名处理样式 */
.post-navigation {
  display: flex;
  justify-content: space-between;
  margin-top: 2rem;
}

.post-navigation a {
  padding: 0.5rem 1rem;
  background: #f0f0f0;
}

.post-navigation .disabled {
  color: #999;
  cursor: not-allowed;
}
  1. 边界情况处理
// 处理删除的文章
if (!currentPost[0]) {
  return c.html(<ErrorPage message="文章不存在" />, 404)
}

性能优化建议

  1. 数据库索引
-- 为 publish_time 和 id 创建复合索引
CREATE INDEX idx_posts_ordering ON posts (publish_time, id);
  1. 合并查询
// 使用 UNION 合并查询减少数据库请求
const [results] = await pool.query(`
  (SELECT 'previous' AS type, id, title 
   FROM posts 
   WHERE publish_time < ? 
   ORDER BY publish_time DESC LIMIT 1)
  UNION ALL
  (SELECT 'next' AS type, id, title 
   FROM posts 
   WHERE publish_time > ? 
   ORDER BY publish_time ASC LIMIT 1)
`, [postTime, postTime]);
  1. 缓存策略
// 使用内存缓存(示例使用 lru-cache)
import LRU from 'lru-cache'

const postCache = new LRU({
  max: 100,
  ttl: 1000 * 60 * 5 // 5分钟
})

app.get('/post/:id', async (c) => {
  const id = c.req.param('id')
  const cached = postCache.get(id)
  if (cached) return c.html(cached)
  
  // ...查询数据库...
  postCache.set(id, renderedHtml)
})

完整工作流程

  1. 用户访问 /post/123
  2. 服务端查询 ID 为 123 的文章内容
  3. 并行查询该文章的前后相邻文章
  4. 组合数据传递给 JSX 模板
  5. 根据上下文是否存在渲染不同的导航链接
  6. 最终生成包含完整导航的 HTML 页面

这个实现方案具有以下特点:

  • 清晰的上下文导航展示
  • 安全的数据库查询防注入
  • 响应式的 HTML 结构
  • 友好的错误处理机制
  • 性能优化扩展点 hono.js  使用mysql 查询博客文章上下文并显示