📚前言
这一章是临时测试,测试完成后,会恢复成测试前的状态,大家可以自己选择是否进行测试。
在前一章代码的基础上进行:
目标:
测试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 token
const 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 token
const 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 {
// 从请求头获取token
const token = req.header('Authorization')?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({ error: '访问被拒绝,请提供有效的token' });
}
// 验证token
const 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;
创建文件总结
✅ 已创建的文件:
-
`tasks.js` - 任务管理API路由
-
`Task.js` - 任务数据模型
-
`auth.js` - 认证中间件
✅ 已存在的文件:
-
`auth.js` - 用户认证路由
-
`User.js` - 用户数据模型
-
`app.js` - 主应用文件

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

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

测试恢复

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