【Trae+AI】和Trae学习搭建App_01(附加可略过):测试Trae的后端功能
📚前言
这一章是临时测试,测试完成后,会恢复成测试前的状态,大家可以自己选择是否进行测试。
在前一章代码的基础上进行:
和Trae学习搭建App_01:项目架构设计与环境搭建
目标:
测试Trae如何实际进行后端开发。
Trae后端开发实战演示
1. 创建Express服务器主文件(backend\src\app.js)
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
require('dotenv').config();const app = express();
const PORT = process.env.PORT || 3000;// 中间件配置
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));// 数据库连接
mongoose.connect(process.env.MONGODB_URI, {useNewUrlParser: true,useUnifiedTopology: true,
})
.then(() => console.log('MongoDB连接成功'))
.catch(err => console.error('MongoDB连接失败:', err));// 路由导入
const authRoutes = require('./routes/auth');
const taskRoutes = require('./routes/tasks');// 使用路由
app.use('/api/auth', authRoutes);
app.use('/api/tasks', taskRoutes);// 健康检查端点
app.get('/health', (req, res) => {res.status(200).json({ status: 'OK', timestamp: new Date().toISOString(),service: 'Todo App Backend'});
});// 404处理
app.use('*', (req, res) => {res.status(404).json({ error: '接口不存在' });
});// 错误处理中间件
app.use((err, req, res, next) => {console.error(err.stack);res.status(500).json({ error: '服务器内部错误' });
});app.listen(PORT, () => {console.log(`服务器运行在端口 ${PORT}`);console.log(`环境: ${process.env.NODE_ENV}`);
});module.exports = app;
2. 创建用户认证路由(backend\src\routes\auth.js)
const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const User = require('../models/User');const router = express.Router();// 用户注册
router.post('/register', async (req, res) => {try {const { username, email, password } = req.body;// 验证输入if (!username || !email || !password) {return res.status(400).json({ error: '请填写所有必填字段' });}// 检查用户是否已存在const existingUser = await User.findOne({ email });if (existingUser) {return res.status(400).json({ error: '该邮箱已被注册' });}// 加密密码const saltRounds = 10;const hashedPassword = await bcrypt.hash(password, saltRounds);// 创建新用户const user = new User({username,email,password: hashedPassword,});await user.save();// 生成JWT tokenconst token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { expiresIn: '24h' });res.status(201).json({message: '用户注册成功',token,user: {id: user._id,username: user.username,email: user.email}});} catch (error) {console.error('注册错误:', error);res.status(500).json({ error: '注册失败,请稍后重试' });}
});// 用户登录
router.post('/login', async (req, res) => {try {const { email, password } = req.body;if (!email || !password) {return res.status(400).json({ error: '请提供邮箱和密码' });}// 查找用户const user = await User.findOne({ email });if (!user) {return res.status(401).json({ error: '邮箱或密码错误' });}// 验证密码const isPasswordValid = await bcrypt.compare(password, user.password);if (!isPasswordValid) {return res.status(401).json({ error: '邮箱或密码错误' });}// 生成JWT tokenconst token = jwt.sign({ userId: user._id },process.env.JWT_SECRET,{ expiresIn: '24h' });res.json({message: '登录成功',token,user: {id: user._id,username: user.username,email: user.email}});} catch (error) {console.error('登录错误:', error);res.status(500).json({ error: '登录失败,请稍后重试' });}
});module.exports = router;
3. 创建用户数据模型(backend\src\models\User.js)
const mongoose = require('mongoose');const userSchema = new mongoose.Schema({username: {type: String,required: [true, '用户名是必填项'],trim: true,minlength: [2, '用户名至少2个字符'],maxlength: [30, '用户名不能超过30个字符']},email: {type: String,required: [true, '邮箱是必填项'],unique: true,lowercase: true,match: [/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/, '请输入有效的邮箱地址']},password: {type: String,required: [true, '密码是必填项'],minlength: [6, '密码至少6个字符']},createdAt: {type: Date,default: Date.now},updatedAt: {type: Date,default: Date.now}
});// 更新时自动设置updatedAt
userSchema.pre('save', function(next) {this.updatedAt = Date.now();next();
});// 移除密码字段的JSON输出
userSchema.methods.toJSON = function() {const user = this.toObject();delete user.password;return user;
};module.exports = mongoose.model('User', userSchema);
4. 创建任务路由文件(backend\src\routes\tasks.js)
const express = require('express');
const Task = require('../models/Task');
const auth = require('../middleware/auth');const router = express.Router();// 获取所有任务(需要认证)
router.get('/', auth, async (req, res) => {try {const tasks = await Task.find({ user: req.userId }).sort({ createdAt: -1 });res.json(tasks);} catch (error) {console.error('获取任务列表错误:', error);res.status(500).json({ error: '获取任务失败' });}
});// 创建新任务(需要认证)
router.post('/', auth, async (req, res) => {try {const { title, description, category, dueDate, priority } = req.body;if (!title) {return res.status(400).json({ error: '任务标题是必填项' });}const task = new Task({title,description: description || '',category: category || '默认',dueDate: dueDate || null,priority: priority || '中等',user: req.userId,completed: false});await task.save();res.status(201).json(task);} catch (error) {console.error('创建任务错误:', error);res.status(500).json({ error: '创建任务失败' });}
});// 更新任务(需要认证)
router.put('/:id', auth, async (req, res) => {try {const { title, description, category, dueDate, priority, completed } = req.body;const task = await Task.findOne({ _id: req.params.id, user: req.userId });if (!task) {return res.status(404).json({ error: '任务不存在' });}// 更新字段if (title !== undefined) task.title = title;if (description !== undefined) task.description = description;if (category !== undefined) task.category = category;if (dueDate !== undefined) task.dueDate = dueDate;if (priority !== undefined) task.priority = priority;if (completed !== undefined) task.completed = completed;task.updatedAt = new Date();await task.save();res.json(task);} catch (error) {console.error('更新任务错误:', error);res.status(500).json({ error: '更新任务失败' });}
});// 删除任务(需要认证)
router.delete('/:id', auth, async (req, res) => {try {const task = await Task.findOneAndDelete({ _id: req.params.id, user: req.userId });if (!task) {return res.status(404).json({ error: '任务不存在' });}res.json({ message: '任务删除成功' });} catch (error) {console.error('删除任务错误:', error);res.status(500).json({ error: '删除任务失败' });}
});// 标记任务完成/未完成(需要认证)
router.patch('/:id/toggle', auth, async (req, res) => {try {const task = await Task.findOne({ _id: req.params.id, user: req.userId });if (!task) {return res.status(404).json({ error: '任务不存在' });}task.completed = !task.completed;task.updatedAt = new Date();await task.save();res.json(task);} catch (error) {console.error('切换任务状态错误:', error);res.status(500).json({ error: '切换任务状态失败' });}
});module.exports = router;
5. 创建任务数据模型(backend\src\models\Task.js)
const mongoose = require('mongoose');const taskSchema = new mongoose.Schema({title: {type: String,required: [true, '任务标题是必填项'],trim: true,minlength: [1, '任务标题不能为空'],maxlength: [200, '任务标题不能超过200个字符']},description: {type: String,maxlength: [1000, '任务描述不能超过1000个字符'],default: ''},category: {type: String,default: '默认',trim: true},priority: {type: String,enum: ['低', '中等', '高'],default: '中等'},completed: {type: Boolean,default: false},dueDate: {type: Date,validate: {validator: function(value) {return !value || value > new Date();},message: '截止日期必须是将来时间'}},user: {type: mongoose.Schema.Types.ObjectId,ref: 'User',required: true},createdAt: {type: Date,default: Date.now},updatedAt: {type: Date,default: Date.now}
});// 更新时自动设置updatedAt
taskSchema.pre('save', function(next) {this.updatedAt = new Date();next();
});// 创建索引以提高查询性能
taskSchema.index({ user: 1, createdAt: -1 });
taskSchema.index({ user: 1, completed: 1 });
taskSchema.index({ user: 1, category: 1 });module.exports = mongoose.model('Task', taskSchema);
6. 创建认证中间件(backend\src\middleware\auth.js)
const jwt = require('jsonwebtoken');
const User = require('../models/User');const auth = async (req, res, next) => {try {// 从请求头获取tokenconst token = req.header('Authorization')?.replace('Bearer ', '');if (!token) {return res.status(401).json({ error: '访问被拒绝,请提供有效的token' });}// 验证tokenconst decoded = jwt.verify(token, process.env.JWT_SECRET);// 查找用户const user = await User.findById(decoded.userId);if (!user) {return res.status(401).json({ error: 'token无效,用户不存在' });}// 将用户信息添加到请求对象中req.userId = user._id;req.user = user;next();} catch (error) {console.error('认证中间件错误:', error);if (error.name === 'JsonWebTokenError') {return res.status(401).json({ error: '无效的token' });}if (error.name === 'TokenExpiredError') {return res.status(401).json({ error: 'token已过期' });}res.status(500).json({ error: '认证失败' });}
};module.exports = auth;
创建文件总结
✅ 已创建的文件:
1. `tasks.js` - 任务管理API路由
2. `Task.js` - 任务数据模型
3. `auth.js` - 认证中间件
✅ 已存在的文件:
- `auth.js` - 用户认证路由
- `User.js` - 用户数据模型
- `app.js` - 主应用文件

启动服务器
在终端运行命令:
# 进入后端目录
cd e:\99mydata\traeplace\app\backend# 安装依赖
npm install# 启动开发服务器
npm run dev
执行界面参考:

✍️说明:没有连上数据库是正常的,因为还没有配置
web测试:
在浏览器上,输入检查地址:localhost:3000/health

测试恢复

恢复后,测试创建的文件被删除了,文件夹还保留了下来,如下图:

