报错:

代码:controllers层:
const router = require("../routes/guestBookRoutes");
const guestbookDAO = require("../models/guestbookModel");
const dbDAO = new guestbookDAO("guestbook.db");
//调用model层的constructor方法(构造函数)
// 创建了一个实例对象dbDAO,用于操作嵌入式数据库。
// const dbDAO = new guestbookDAO();
// 创建了一个实例对象dbDAO,用于操作嵌入式数据库。
exports.landing_page = function (req, res) {
res.send("Hello! Welcome to my application!");
// dbDAO.init();
//初始化数据库,即在内存中创建一个空的数组。
};
exports.entries_list = function (req, res) {
// res.send("<h1>Guestbook</h1>");
dbDAO
.getAllEntries()
.then((list) => {
//then拿到promise对象,list是resolve的值,也就是数据库中的所有记录。
res.render("entries", {
//渲染名为entries的视图
title: "Guestbook",
//要渲染的内容,key:value形式,
//这里的key是mustache文件的title,value是每个循环中的内容,
// 也就是想显示的内容。
entries: list,
//这里的entries要和mustache文件中的{{#entries}}对应起来。
//这里的list是数据库中的所有记录,要和mustache文件中的{{entries}}对应起来。
});
})
.catch((err) => {
console.log("err:", err);
}); //catch在then后面,捕获then中的错误。
};
exports.peter_entries = function (req, res) {
res.send("<h1>Processing Peter's Entries, see terminal</h1>");
dbDAO
.getPetersEntries()
.then((list1) => {
//then拿到promise对象,list是resolve的值,也就是数据库中的所有记录。
res.render("entries_p", {
//渲染名为entries的视图
title: "Peter's Guest Book",
//要渲染的内容,key:value形式,
//这里的key是mustache文件的title,value是每个循环中的内容,
// 也就是想显示的内容。
entries_p: list1,
//这里的entries要和mustache文件中的{{#entries}}对应起来。
//这里的list是数据库中的所有记录,要和mustache文件中的{{entries}}对应起来。
});
})
.catch((err) => {
console.log("err:", err);
});
};
exports.show_new_entry = function (req, res) {
res.render("newEntry", {
title: "New Entry",
});
};
exports.post_new_entry = function (req, res) {
if (!req.body.author || !req.body.subject || !req.body.contents) {
res.status(400).send("Author不能为空!");
return;
}
dbDAO.addEntry(req.body.author, req.body.subject, req.body.contents);
//跟name属性对应
res.redirect("/guestbook");
};
exports.show_user_entries = function (req, res) {
let user = req.params.author; // URL:后的内容,是个形参
dbDAO
.getUserEntries(user)
.then((list) => {
//then拿到promise对象,list是resolve的值,也就是数据库中的所有记录。
res.render("entries", {
//渲染名为entries的视图
title: user + " Guestbook",
//要渲染的内容,key:value形式,
//这里的key是mustache文件的title,value是每个循环中的内容,
// 也就是想显示的内容。
entries: list,
//这里的entries要和mustache文件中的{{#entries}}对应起来。
//这里的list是数据库中的所有记录,要和mustache文件中的{{entries}}对应起来。
});
})
.catch((err) => {
console.log("err:", err);
}); //catch在then后面,捕获then中的错误。
};
exports.update_entry = function (req, res) {
const _id = req.params.id;
dbDAO
.updateEntry(_id)
.then((list) => {
//then拿到promise对象,list是resolve的值,也就是数据库中的所有记录。
res.render("update", {
//渲染名为entries的视图
title: user + " Update Guestbook",
//要渲染的内容,key:value形式,
//这里的key是mustache文件的title,value是每个循环中的内容,
// 也就是想显示的内容。
entries: list,
//这里的entries要和mustache文件中的{{#entries}}对应起来。
//这里的list是数据库中的所有记录,要和mustache文件中的{{entries}}对应起来。
});
})
.catch((err) => {
console.log("err:", err);
}); //catch在then后面,捕获then中的错误。
// res.redirect("/guestbook");
};
exports.show_update_entry = function (req, res) {
const _id = req.params.id; // 从URL获取参数
// 查询数据库获取要更新的条目(需确保`getEntryById`方法存在)
dbDAO
.getEntryById(_id) // 假设模型层有此方法
.then((entry) => {
if (!entry) {
return res.status(404).send("Entry not found");
}
res.render("update", {
title: "Update Entry",
id: _id, // 将ID传递给视图
entry: entry, // 将条目数据传递给视图
});
})
.catch((err) => {
console.error("Error fetching entry for update:", err);
res.status(500).send("Internal Server Error");
});
};
exports.delete_entry = function (req, res) {
const _id = req.params.id;
dbDAO
.deleteEntry(_id)
.then((list) => {
//then拿到promise对象,list是resolve的值,也就是数据库中的所有记录。
res.redirect("/guestbook");
})
.catch((err) => {
console.log("err:", err);
}); //catch在then后面,捕获then中的错误。
};
// exports.new_entry = function (req, res) {
// res.send("<h1>Not yet implemented:show a new entry page.</h1>");
// dbDAO.init();
// };
exports.show_user_entries;
exports.about_page = function (req, res) {
// 返回位于public文件夹下的about.html文件
res.redirect("about.html");
//直接重定向,app.use(express.static(public));的作用
dbDAO.init();
};
exports.image = function (req, res) {
// 返回位于public/img/logo.jpg的图片文件
res.redirect("logo.jpg");
dbDAO.init();
};
exports.status_404 = function (req, res) {
res.status(404); // 设置HTTP状态码为404
res.send("Oops! Page not found."); // 返回错误提示
};
exports.status_500 = function (err, req, res, next) {
console.log("error:", err);
res.status(500);
res.type("text/plain");
res.send("Internal Server Error");
};
router层:
const express = require("express");
const { entries_list } = require("../controllers/guestbookControllers");
const router = express.Router();
const controllers = require("../controllers/guestbookControllers");
router.get("/", controllers.landing_page);
router.get("/guestbook", controllers.entries_list);
router.get("/peter", controllers.peter_entries);
router.get("/new", controllers.show_new_entry);
router.get("/posts/:author", controllers.show_user_entries);
router.get("/update/:id", controllers.show_update_page);
router.post("/update/:id", controllers.update_entry);
router.post("/delete/:id", controllers.delete_entry);
//加上:变成一个变量,可以匹配任何东西
// router.get("/posts", controller.get("/posts", function (request, response) {
// console.log("filtering for author ", request.query.author);
// }));
router.post("/new", controllers.post_new_entry);
router.get("/about", controllers.about_page);
router.get("/img/logo.jpg", controllers.image);
router.use(controllers.status_404);
router.use(controllers.status_500);
module.exports = router; //导出路由,非常重要
model层:
const nedb = require("@seald-io/nedb"); //nedb是一个变量
class GuestBook {
constructor(dbFilePath) {
if (dbFilePath) {
this.db = new nedb({ filename: dbFilePath, autoload: true });
//db是该对象的一个属性,用来存储该数据库的引用信息。
console.log("DB created:" + dbFilePath);
} else {
this.db = new nedb();
}
}
init() {
this.db.insert(
{
subject: "I liked the exhibition",
contents: "nice",
published: "2020-02-16",
author: "Peter",
},
function (err, newDoc) {
if (err) {
console.log("Error:" + err);
} else {
console.log("Peter inserted!");
}
}
);
this.db.insert(
{
subject: "Didn't like it",
contents: "A really terrible style!",
published: "2020-02-18",
author: "Ann",
},
function (err, newDoc) {
if (err) {
console.log("Error:" + err);
} else {
console.log("Ann inserted!");
}
}
);
}
addEntry(author_value, subject_value, contents_value) {
this.db.insert(
{
subject: subject_value,
contents: contents_value,
published: new Date().toISOString().split("T")[0],
author: author_value,
},
function (err, newDoc) {
if (err) {
console.log("Error:" + err);
} else {
console.log("日期为:" + new Date().toISOString());
console.log("addEntry inserted!");
}
}
);
}
getAllEntries() {
//return a Promise object, which can be resolved or rejected
return new Promise((resolve, reject) => {
//Promise对象可以记录异步操作是成功还是失败
//resolve记录成功时的状态,reject记录失败时的报错信息,
// 同时变化了Promise的状态。
//避免回调地狱,用Promise代替回调函数。
this.db.find({}, function (err, entries) {
if (err) {
reject(err);
console.log("getAllEntries Promise rejected:" + err);
} else {
resolve(entries);
console.log("getAllEntries Promise resolved: ", entries);
}
});
});
}
getPetersEntries() {
return new Promise((resolve, reject) => {
this.db.find({ author: "Peter" }, function (err, entries_p) {
if (err) {
reject(err);
console.log("getPetersEntries Promise rejected:" + err);
} else {
resolve(entries_p);
console.log("getPetersEntries Promise resolved:", entries_p);
}
});
});
}
getUserEntries(userName) {
return new Promise((resolve, reject) => {
this.db.find({ author: userName }, function (err, entries_u) {
if (err) {
reject(err);
console.log("getUserEntries Promise rejected:" + err);
} else {
resolve(entries_u);
console.log("getUserEntries Promise resolved:", entries_u);
}
});
});
}
updateEntry(userID, author, contents) {
return new Promise((resolve, reject) => {
this.db.update(
{ _id: userID },
{
$set: {
author: req.body.author, // 从表单获取数据
contents: req.body.contents,
published: new Date().toISOString().split("T")[0],
// 注意这里的写法,$set是用来更新数据的,而不是直接赋值。
// 这样可以避免覆盖掉其他字段的数据。
},
},
function (err, updatedDoc) {
if (err) {
reject(err);
console.log("updateEntry Promise rejected:" + err);
} else {
resolve(updatedDoc);
console.log("updateEntry Promise resolved:", updatedDoc);
}
}
);
});
}
deleteEntry(userID) {
return new Promise((resolve, reject) => {
this.db.delete({ _id: userID }, function (err, db_deleted) {
if (err) {
reject(err);
console.log("deleteEntry Promise rejected:" + err);
} else {
resolve(db_deleted);
console.log("deleteEntry Promise resolved:", +userID + " deleted");
}
});
});
}
}
module.exports = GuestBook;
view层:
entries.mustache:
<html lang="en">
<head>
{{>header}}
</head>
<body class="container">
//read-only不可编辑
//点修改按钮,id作为参数,找到对应记录,跳转到对应mustache
//作者只能修改自己的,对应登录的名字
//删除要弹出警告框,避免误操作
<h1>{{title}}</h1>
<div class="text-right">
<a href="/new" class="btn btn-primary">
Write in the guest book
</a>
</div>
{{#entries}}
<div class="card">
<div class="card-header">
{{subject}}
</div>
<div class="card-body">
<div class="card-text">
{{contents}}
</div>
<div class="card-text">
Written by <a href="/posts/{{author}}">{{author}}</a>,on {{published}}
<a href="/update/{{id}}" >修改</a>
<!-- 修改删除链接为表单 -->
<form action="/delete/{{id}}" method="post">
<button type="submit" class="delete-btn">删除</button>
</form>
</div>
</div>
</div>
{{/entries}}
{{^entries}}
No entries yet!
{{/entries}}
</body>
</html>
{! <div class="card-text">
{! Written by <a href="/posts/?author={{author}}">{{author}}</a>, on
{! {{published}}
{! </div>
update.mustache:
<!DOCTYPE html>
<html lang="en">
<head>
{{>header}}
</head>
<body class="container">
<h1>{{title}}</h1>
<form action="/update/{{id}}" method="post" role="form">
<div class="form-group">
<label for="author">Author</label>
<input
type="text"
class="form-control"
id="author"
name="author"//每一个框一定要有一个name属性
value="{{entry.author}}"
required
/>
</div>
<div class="form-group">
<label for="subject">Subject</label>
<input
type="text"
class="form-control"
id="subject"
name="subject"
value="{{subject}}"
required
/>
</div>
<div class="form-group">
<label for="contents">Entry text</label>
<textarea
class="form-control"
id="contents"
name="contents"
value="{{contents}}"
rows="3"
required
>
{{entry.contents}}
</textarea>
</div>
<div class="form-group">
<input type="submit" value="Post entry" class="btn btn-primary" />
</div>
</form>
</body>
</html>