Koa+MongoDB 实战:从零到一打造电影资讯网站

介绍

随着互联网技术的发展,越来越多的人开始使用网站获取资讯。电影作为一种重要的文化艺术形式,也有着广泛的受众。本文将详细介绍如何使用 Koa 和 MongoDB 技术打造一个电影资讯网站。

准备工作

在开始前端开发的过程中,需要准备以下环境:

  • Node.js:本项目使用 Node.js 作为后端环境。
  • MongoDB:本项目使用 MongoDB 作为数据库。
  • Koa:本项目使用 Koa 作为后端框架。

在完成上述准备工作后,我们可以开始着手构建项目了。

构建项目

初始化项目

我们首先需要创建一个项目,可以采用如下命令:

mkdir movie
cd movie
npm init -y

这个命令在当前目录下创建一个名为 movie 的文件夹,并初始化一个 package.json 文件,用于记录项目的信息。

安装依赖

我们需要安装项目的依赖包,包括 MongoDB 驱动程序和 Koa 框架。可以采用如下命令:

npm install koa mongodb

创建服务器

我们可以在项目根目录下创建一个名为 app.js 的文件,作为我们的服务器程序。

首先,我们需要导入 Koa 框架和 MongoDB 驱动程序:

const Koa = require("koa");
const MongoClient = require("mongodb").MongoClient;
const { ObjectId } = require("mongodb");

然后,我们需要初始化 Koa 应用程序,并连接 MongoDB 数据库:

const app = new Koa();
const url = "mongodb://localhost:27017/movie";
MongoClient.connect(url, (err, client) => {
  if (err) {
    console.log(err);
    return;
  }
  console.log("Connected to MongoDB");
  const db = client.db("movie");
  app.context.db = db;
});

接下来,我们可以在 Koa 应用程序中定义路由规则,例如:

app.use(async (ctx, next) => {
  switch (ctx.request.method) {
    case "GET":
      switch (ctx.request.url) {
        case "/movies":
          await listMovies(ctx);
          break;
        case /^\/movies\/(.+)$/.test(ctx.request.url) && ctx.request.url:
          await getMovie(ctx);
          break;
        default:
          ctx.response.status = 404;
          ctx.response.body = { error: "Not found" };
          break;
      }
      break;
    case "POST":
      switch (ctx.request.url) {
        case "/movies":
          await createMovie(ctx);
          break;
        default:
          ctx.response.status = 404;
          ctx.response.body = { error: "Not found" };
          break;
      }
      break;
    case "PUT":
      switch (ctx.request.url) {
        case "/movies":
          await updateMovie(ctx);
          break;
        default:
          ctx.response.status = 404;
          ctx.response.body = { error: "Not found" };
          break;
      }
      break;
    case "DELETE":
      switch (ctx.request.url) {
        case /^\/movies\/(.+)$/.test(ctx.request.url) && ctx.request.url:
          await deleteMovie(ctx);
          break;
        default:
          ctx.response.status = 404;
          ctx.response.body = { error: "Not found" };
          break;
      }
      break;
    default:
      ctx.response.status = 405;
      ctx.response.body = { error: "Method not allowed" };
      break;
  }
});

其中,listMoviesgetMoviecreateMovieupdateMoviedeleteMovie 分别对应电影列表、电影详情、新增电影、更新电影和删除电影的操作。

最后,我们需要在 Koa 应用程序上启动 HTTP 服务器:

const port = 3000;
app.listen(port, () => {
  console.log(`Server started on port ${port}`);
});

实现电影列表和电影详情

我们可以在 app.js 中实现 listMoviesgetMovie 方法:

const listMovies = async (ctx) => {
  const db = ctx.db;
  const collection = db.collection("movies");
  const movies = await collection.find().toArray();
  ctx.response.body = movies;
};

const getMovie = async (ctx) => {
  const db = ctx.db;
  const collection = db.collection("movies");
  const id = ctx.request.url.match(/^\/movies\/(.+)$/)[1];
  const movie = await collection.findOne({ _id: ObjectId(id) });
  if (movie) {
    ctx.response.body = movie;
  } else {
    ctx.response.status = 404;
    ctx.response.body = { error: "Movie not found" };
  }
};

这两个方法分别对应电影列表和电影详情页面的接口,我们可以在浏览器中访问 http://localhost:3000/movieshttp://localhost:3000/movies/<id> 查看结果。

实现新增电影、更新电影和删除电影

我们可以继续在 app.js 中实现 createMovieupdateMoviedeleteMovie 方法:

const createMovie = async (ctx) => {
  const db = ctx.db;
  const collection = db.collection("movies");
  const movie = ctx.request.body;
  if (!movie.title || !movie.releaseDate || !movie.posterUrl) {
    ctx.response.status = 400;
    ctx.response.body = { error: "Missing fields" };
    return;
  }
  const result = await collection.insertOne(movie);
  movie._id = result.insertedId;
  ctx.response.status = 201;
  ctx.response.body = movie;
};

const updateMovie = async (ctx) => {
  const db = ctx.db;
  const collection = db.collection("movies");
  const movie = ctx.request.body;
  if (!movie._id || !movie.title || !movie.releaseDate || !movie.posterUrl) {
    ctx.response.status = 400;
    ctx.response.body = { error: "Missing fields" };
    return;
  }
  const result = await collection.updateOne(
    { _id: ObjectId(movie._id) },
    { $set: movie }
  );
  if (result.modifiedCount === 1) {
    ctx.response.status = 200;
    ctx.response.body = movie;
  } else {
    ctx.response.status = 404;
    ctx.response.body = { error: "Movie not found" };
  }
};

const deleteMovie = async (ctx) => {
  const db = ctx.db;
  const collection = db.collection("movies");
  const id = ctx.request.url.match(/^\/movies\/(.+)$/)[1];
  const result = await collection.deleteOne({ _id: ObjectId(id) });
  if (result.deletedCount === 1) {
    ctx.response.status = 204;
  } else {
    ctx.response.status = 404;
    ctx.response.body = { error: "Movie not found" };
  }
};

这三个方法分别对应新增电影、更新电影和删除电影的操作,我们可以在浏览器中使用 HTTP POST、PUT 和 DELETE 请求来访问这些接口。

创建前端界面

我们可以在 movie 目录下创建一个名为 index.html 的文件,用于展示电影列表和电影详情页面。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Movie</title>
  </head>
  <body>
    <h1>Movie</h1>
    <ul id="movies"></ul>
    <div id="movie"></div>
    <form>
      <h2>New Movie</h2>
      <div>
        <label>Title:</label>
        <input type="text" name="title" required />
      </div>
      <div>
        <label>Release Date:</label>
        <input type="date" name="releaseDate" required />
      </div>
      <div>
        <label>Poster Url:</label>
        <input type="url" name="posterUrl" required />
      </div>
      <button type="submit">Create</button>
    </form>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script>
      const moviesEl = document.getElementById("movies");
      const movieEl = document.getElementById("movie");
      const formEl = document.querySelector("form");

      const renderMovie = (movie) => {
        movieEl.innerHTML = "";
        const titleEl = document.createElement("h2");
        titleEl.textContent = movie.title;
        movieEl.appendChild(titleEl);
        const releaseDateEl = document.createElement("div");
        releaseDateEl.textContent = `Release Date: ${movie.releaseDate}`;
        movieEl.appendChild(releaseDateEl);
        const posterUrlEl = document.createElement("div");
        posterUrlEl.innerHTML = `Poster Url: <img src="${movie.posterUrl}" width="200"/>`;
        movieEl.appendChild(posterUrlEl);
      };

      const renderMovies = (movies) => {
        moviesEl.innerHTML = "";
        for (const movie of movies) {
          const liEl = document.createElement("li");
          const aEl = document.createElement("a");
          aEl.href = `#${movie._id}`;
          aEl.textContent = movie.title;
          aEl.addEventListener("click", async (event) => {
            event.preventDefault();
            const response = await axios.get(`/movies/${movie._id}`);
            const movie = response.data;
            renderMovie(movie);
          });
          liEl.appendChild(aEl);
          moviesEl.appendChild(liEl);
        }
      };

      const fetchMovies = async () => {
        const response = await axios.get("/movies");
        const movies = response.data;
        renderMovies(movies);
      };

      const createMovie = async (event) => {
        event.preventDefault();
        const movie = {
          title: formEl.title.value,
          releaseDate: formEl.releaseDate.value,
          posterUrl: formEl.posterUrl.value,
        };
        try {
          const response = await axios.post("/movies", movie);
          const createdMovie = response.data;
          formEl.reset();
          await fetchMovies();
          window.location.hash = `#${createdMovie._id}`;
          const getMovieResponse = await axios.get(
            `/movies/${createdMovie._id}`
          );
          const movie = getMovieResponse.data;
          renderMovie(movie);
        } catch (error) {
          console.log(error.response.data.error);
        }
      };

      fetchMovies();
      formEl.addEventListener("submit", createMovie);
    </script>
  </body>
</html>

这个 HTML 文件使用了 Axios 库来实现与后端接口的通信,使用了基础的 HTML、CSS 和 JavaScript 实现了电影列表和电影详情的页面展示,以及新增电影的表单提交。

运行项目

我们可以采用如下命令在根目录下启动服务器:

node app.js

然后可以在浏览器中访问 http://localhost:3000 来查看电影资讯网站。

总结

本文详细介绍了如何使用 Koa 和 MongoDB 技术打造一个电影资讯网站,并提供了示例代码。通过学习本文,读者可以了解到如何在前端领域中使用 Koa 和 MongoDB 技术,熟悉基本的后端开发流程,以及如何实现基本的前端界面。本文的内容具有深度和学习以及指导意义,可以为前端开发人员提供有用的参考。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/658fe143eb4cecbf2d56ff4b


纠错
反馈