听说ChatGPT能教我做全栈?

256 阅读3分钟

最近总是想不好中午吃什么。就想着自己写个小程序,解决一下我的选择困难症,抽到什么吃什么。作为一个卑微前端,写个页面自然是没问题的,可是后端接口怎么办呢?这不是有ChatGPT嘛!

体验

先看成果:

image.png

技术选型

小程序页面

微信小程序的语法感觉还是很丑陋,不是很想用,还是想写React,所以前端选择了使用Taro框架和VantUI进行开发,因为本文的重点在于后端,这里的开发步骤就先略过啦~

后端框架

好啦,这里开始,就全程让ChatGPT接管吧,先来问问它技术选型吧:

chat技术选型.png 看下来好像node.js + express.js的技术栈很适合我,就选它,可是数据库咋办呢?继续问:

image.png 我就写个小程序而已,MongoDB好像够用了,就他吧。

在ChatGPT的帮助下,我选择了 Express.js + MongoDB作为我的后端开发框架。

编写后端接口

在开始让chatGPT开始写代码之前,我们可以自己定一下数据结构,这个简单的小程序也不需要什么登录态,不过一个唯一标识还是要有的,就用微信登陆接口返回的openid做唯一标识吧,那么我的数据结构应该是这样:

User {
    openid:String
    nickname: String,
    avatar: String,
    foodList: [
        {
          imageUrl: String,
          name: String,
          location: String,
          // 具体时间
          date: { type: Date, default: Date.now },
        },
    ],
}

接下来就用这个简单的数据结构,让chatGPT帮我写一套增删改查的接口吧。 首先要为每一位登录的用户设置一个标识,也就是openid,根据微信小程序开发文档,openid要在后台调用接口来获取。

image.png 开始问问chatGPT吧: image.png

image.png

image.png 真是贴心,连前端代码都写好了。再让他把增删改查接口一并写好吧,最后再一起测。 不过我感觉到一点隐患,它好像喜欢把代码写在同一个文件里,不行,良好的编码习惯还是要有,得让他把代码结构规范一下。

image.png 看来确实有点东西啊,篇幅原因就不一一截图了,直接把chatGPT生成的代码贴出来:

**models/user.js**:
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  openid: String,
  nickname: String,
  avatar: String,
  foodList: [{
    imageUrl: String,
    name: String,
    location: String,
    date: { type: Date, default: Date.now }
  }]
});

module.exports = mongoose.model('User', userSchema);


**controllers/foodListController.js**:
const User = require('../models/user');

// 添加食物记录
exports.addFood = async (req, res) => {
  const { openid, name, imageUrl, location } = req.body;

  try {
    const user = await User.findOne({ openid });
    if (!user) {
      return res.status(404).json({ error: "用户不存在" });
    }
    const newFoodRecord = { name, imageUrl, location };
    const filteredRecord = Object.fromEntries(
      Object.entries(newFoodRecord).filter(
        ([key, value]) => value !== undefined
      )
    );
    await user.updateOne({ $push: { foodList: filteredRecord } });
    res.status(200).json({
      success: true,
      resMsg: "保存成功",
    });
  } catch (err) {
    res.status(500).json({ error: "数据更新失败" });
  }
};

// 获取食物记录列表
exports.getFoodList = async (req, res) => {
  const { openid } = req.body;

  try {
    const user = await User.findOne({ openid });
    if (!user) {
      return res.status(404).json({ error: "用户不存在" });
    }
    const { foodList = [] } = user;

    foodList.sort((a, b) => b.date - a.date);

    res.status(200).json({
      foodList: foodList,
    });
  } catch (err) {
    res.status(500).json({ error: "数据查询失败" });
  }
};

// 更新食物
exports.updateFood = async (req, res) => {
  const { openid, recordId, updatedFields } = req.body;
  try {
    const user = await User.findOne({ openid });

    if (!user) {
      return res.status(404).json({ error: "用户不存在" });
    }

    // 找到要修改的记录在 foodList 数组中的索引
    const indexToUpdate = user.foodList.findIndex(
      (record) => record._id.toString() === recordId
    );

    if (indexToUpdate === -1) {
      return res.status(404).json({ error: "记录不存在" });
    }

    // 构造要更新的字段和值
    const updatedRecord = {
      ...user.foodList[indexToUpdate],
      ...updatedFields,
    };
    const filteredUpdatedRecord = Object.fromEntries(
      Object.entries(updatedRecord).filter(
        ([key, value]) => value !== undefined
      )
    );

    // 更新记录
    user.foodList[indexToUpdate] = filteredUpdatedRecord;

    await user.save();

    res.status(200).json({
      success: true,
      resMsg: "记录已成功更新",
    });
  } catch (err) {
    res.status(500).json({ error: "数据更新失败" });
  }
};

// 删除食物记录
exports.deleteFood = async (req, res) => {
  const { openid, foodName } = req.body;
  try {
    const user = await User.findOne({ openid });
    if (!user) {
      return res.status(404).json({ error: "用户不存在" });
    } else {
      const targetFood = user.foodList.find((food) => food.name === foodName);

      if (targetFood) {
        user.foodList = user.foodList.filter((food) => food.name !== foodName);
        await user.save();
        res.status(200).json({
          success: true,
          resMsg: "删除成功",
        });
      } else {
        res.status(500).json({ error: "数据更新失败" });
      }
    }
  } catch (error) {
    res.status(500).json({ error: "数据更新失败" });
  }
};


**routes/foodListRoutes.js**:
const express = require('express'); const router = express.Router(); const foodListController = require('../controllers/foodListController'); // 添加食物记录 router.post('/:openid/food', foodListController.addFood); // 获取食物记录列表 router.get('/:openid/food', foodListController.getFoodList); // 删除食物记录 router.delete('/:openid/food/:foodId', foodListController.deleteFood); module.exports = router;

**app.js**(主应用文件):
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const userRoutes = require('./routes/userRoutes');
const foodListRoutes = require('./routes/foodListRoutes');

const app = express();
const port = process.env.PORT || 3000;

mongoose.connect('mongodb://localhost:27017/mydatabase', {
  useNewUrlParser: true,
  useUnifiedTopology: true
});

app.use(bodyParser.json());

app.use('/users', userRoutes);
app.use('/users', foodListRoutes);

app.listen(port, () => {
  console.log(`Server is listening on port ${port}`);
});

测试成果

chatGPT生成的代码看起来还挺规范的,命名什么的也都没啥问题,图片上传之类的用的腾讯云的COS,安装一下他们的SDK,复制下示例代码就可以用了,倒也用不上chatGPT帮忙了,最后整理了一下目录,"今天吃什么Pro版"小程序的后台接口就搭建完成啦!

image.png

跟我的前端配合起来看一看:

image.png 看起来登录接口没问题。

image.png 在初始化的时候就写了一些数据,看起来查询接口也没问题。

image.png 很好,新增接口依然没问题。

image.png

image.png

全部完成,chatGPT牛逼!

目前已经把小程序发布上线了,后端的部署也是通过chatGPT的帮助进行,用了我完全不熟悉的docker,将服务部署到了腾讯云服务器,AI的出现确实能减少非常多的重复工作,不过这让我这种菜鸡前端也感到了后怕,说不定真的会有AI淘汰程序员的一天啊😰。