当前位置: 首页 > news >正文

使用React、Express实现一个问卷发布/收集系统

1. 设置项目结构

questionnaire-system/client/             // 前端应用src/components/     // React组件pages/          // 页面App.jsindex.jsserver/             // 后端服务routes/           // 路由models/           // 数据模型app.jspackage.json

2. 启动前端应用

client目录下,创建React应用并启动它:

npx create-react-app .
npm start

3. 设置Express后端

server目录下,设置Express后端:

npm init -y
npm install express mongoose body-parser cors

server/app.js中设置Express应用:

const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const app = express();app.use(cors());
app.use(bodyParser.json());// 设置数据库连接
mongoose.connect("mongodb://localhost/questionnaire", {useNewUrlParser: true,useUnifiedTopology: true,
});
const db = mongoose.connection;
db.on("error", console.error.bind(console, "数据库连接错误"));
db.once("open", function () {console.log("数据库连接成功");
});// 设置路由
const authRoutes = require("./routes/auth");
const questionnaireRoutes = require("./routes/questionnaire");app.use("/auth", authRoutes);
app.use("/questionnaire", questionnaireRoutes);app.listen(5000, () => {console.log("后端服务已启动,端口5000");
});

4. 创建Express路由

server/routes目录下,创建路由文件,例如auth.jsquestionnaire.js,以处理用户身份验证和问卷操作。

创建auth.js用于用户身份验证:

const express = require("express");
const router = express.Router();// 处理用户注册
router.post("/register", (req, res) => {// 实现用户注册逻辑
});// 处理用户登录
router.post("/login", (req, res) => {// 实现用户登录逻辑
});// 处理用户注销
router.post("/logout", (req, res) => {// 实现用户注销逻辑
});module.exports = router;

创建questionnaire.js用于问卷操作:

const express = require("express");
const router = express.Router();// 处理创建问卷
router.post("/create", (req, res) => {// 实现创建问卷逻辑
});// 处理发布问卷
router.post("/publish", (req, res) => {// 实现发布问卷逻辑
});// 处理填写问卷
router.post("/submit", (req, res) => {// 实现填写问卷逻辑
});// 处理查看问卷结果
router.get("/results/:id", (req, res) => {const questionnaireId = req.params.id;// 实现查看问卷结果逻辑
});module.exports = router;

5. 创建数据模型

server/models目录下,创建Mongoose模型来定义用户、问卷等数据结构。

server/models目录下,创建一个名为User.js的文件来定义用户数据模型:

const mongoose = require("mongoose");const userSchema = new mongoose.Schema({username: {type: String,required: true,unique: true,},password: {type: String,required: true,},email: {type: String,required: true,unique: true,},// 其他用户相关字段
});const User = mongoose.model("User", userSchema);module.exports = User;

然后,创建一个名为Questionnaire.js的文件来定义问卷数据模型:

const mongoose = require("mongoose");const questionnaireSchema = new mongoose.Schema({title: {type: String,required: true,},description: String,questions: [{type: mongoose.Schema.Types.ObjectId,ref: "Question",},],// 其他问卷相关字段
});const Questionnaire = mongoose.model("Questionnaire", questionnaireSchema);module.exports = Questionnaire;

在Express应用的server/app.js文件中,确保您已经连接了MongoDB数据库

mongoose.connect("mongodb://localhost/questionnaire", {useNewUrlParser: true,useUnifiedTopology: true,
});

6. 设置React组件和页面

在前端应用中,创建React组件和页面来实现问卷设计、问卷发布、问卷填写、账户管理等功能。

在前端应用中,您需要创建React组件和页面来实现不同的功能,包括问卷设计、问卷发布、问卷填写和账户管理。以下是一个项目结构:

client/src/components/Auth/           // 用户身份验证相关组件Questionnaire/  // 问卷相关组件Account/        // 账户管理相关组件pages/Home.js         // 主页Login.js        // 登录页Register.js     // 注册页CreateQuestionnaire.js  // 创建问卷页FillQuestionnaire.js    // 填写问卷页AccountSettings.js      // 账户设置页App.js             // 主应用组件index.js           // 渲染应用

CreateQuestionnaire.js 代码

import React, { useState } from "react";function CreateQuestionnaire() {const [questionnaire, setQuestionnaire] = useState({title: "",description: "",questions: [],});const addQuestion = () => {// 在状态中添加新问题const newQuestion = {text: "",options: [],};setQuestionnaire((prev) => ({...prev,questions: [...prev.questions, newQuestion],}));};const handleQuestionChange = (index, field, value) => {// 更新特定问题的字段setQuestionnaire((prev) => {const updatedQuestions = [...prev.questions];updatedQuestions[index][field] = value;return { ...prev, questions: updatedQuestions };});};const saveQuestionnaire = () => {// 将问卷数据发送到后端保存// 可以使用Fetch或Axios发送POST请求console.log("保存问卷数据:", questionnaire);};return (<div><h2>Create Questionnaire</h2><div><label>Title:</label><inputtype="text"value={questionnaire.title}onChange={(e) => setQuestionnaire({ ...questionnaire, title: e.target.value })}/></div><div><label>Description:</label><textareavalue={questionnaire.description}onChange={(e) => setQuestionnaire({ ...questionnaire, description: e.target.value })}/></div><h3>Questions</h3>{questionnaire.questions.map((question, index) => (<div key={index}><inputtype="text"placeholder="Enter your question"value={question.text}onChange={(e) => handleQuestionChange(index, "text", e.target.value)}/><button onClick={addQuestion}>Add Question</button></div>))}<button onClick={addQuestion}>Add Question</button><button onClick={saveQuestionnaire}>Save Questionnaire</button></div>);
}export default CreateQuestionnaire;

7. 实现问卷设计和发布

允许用户创建问卷,并将问卷保存到数据库。允许用户发布问卷链接。

  1. 在后端设置一个路由来接收前端发送的问卷数据并将其保存到数据库。
  2. 生成一个唯一的问卷标识符,以便后续用户填写问卷时使用。
  3. 返回问卷的标识符作为发布链接
const express = require("express");
const router = express.Router();
const Questionnaire = require("../models/Questionnaire");// 创建问卷
router.post("/create", async (req, res) => {const { title, description, questions } = req.body;try {const newQuestionnaire = new Questionnaire({title,description,questions,});const savedQuestionnaire = await newQuestionnaire.save();res.json({ questionnaireId: savedQuestionnaire._id });} catch (error) {res.status(500).json({ error: "问卷保存失败" });}
});// ...其他问卷相关路由module.exports = router;

8. 实现问卷填写和收集

用户可以填写问卷,并将答案保存到数据库。

前端实现:

  1. 创建一个页面,显示问卷的问题,并允许用户填写答案。
  2. 用户填写完问卷后,将答案数据发送到后端以进行保存。

下面是FillQuestionnaire.js 组件的更新,以包括保存答案到后端的功能。

import React, { useState } from "react";
import axios from "axios";function FillQuestionnaire({ questionnaireId }) {const [answers, setAnswers] = useState([]);const [questionnaire, setQuestionnaire] = useState(null);// 从后端获取问卷数据useEffect(() => {axios.get(`/api/questionnaire/${questionnaireId}`).then((response) => {setQuestionnaire(response.data);});}, [questionnaireId]);const handleAnswerChange = (questionIndex, answer) => {// 更新答案const updatedAnswers = [...answers];updatedAnswers[questionIndex] = answer;setAnswers(updatedAnswers);};const submitAnswers = () => {// 将答案数据发送到后端保存axios.post(`/api/questionnaire/submit/${questionnaireId}`, { answers }).then((response) => {console.log("答案提交成功", response.data);// 可以进行其他操作,如重定向到感谢页面}).catch((error) => {console.error("答案提交失败", error);});};return (<div>{questionnaire && (<div><h2>{questionnaire.title}</h2><p>{questionnaire.description}</p><form>{questionnaire.questions.map((question, index) => (<div key={index}><p>{question.text}</p>{/* 根据问题类型渲染相应的答案输入框 */}{question.type === "text" ? (<inputtype="text"value={answers[index] || ""}onChange={(e) => handleAnswerChange(index, e.target.value)}/>) : (// 渲染其他类型的答案输入框)}</div>))}</form><button onClick={submitAnswers}>Submit Answers</button></div>)}</div>);
}export default FillQuestionnaire;

后端实现:

  1. 在后端设置一个路由来接收前端发送的答案数据并将其保存到数据库。
  2. 根据问卷标识符,将答案与问卷关联。

以下是一个简化的后端路由 server/routes/questionnaire.js

const express = require("express");
const router = express.Router();
const Questionnaire = require("../models/Questionnaire");// 提交问卷答案
router.post("/submit/:questionnaireId", async (req, res) => {const questionnaireId = req.params.questionnaireId;const answers = req.body.answers;try {const questionnaire = await Questionnaire.findById(questionnaireId);if (!questionnaire) {return res.status(404).json({ error: "问卷不存在" });}// 将答案与问卷关联,保存到数据库// 您可以根据实际需求设计数据库结构来存储答案数据res.json({ message: "答案保存成功" });} catch (error) {res.status(500).json({ error: "答案保存失败" });}
});// ...其他问卷相关路由module.exports = router;

相关文章:

使用React、Express实现一个问卷发布/收集系统

1. 设置项目结构 questionnaire-system/client/ // 前端应用src/components/ // React组件pages/ // 页面App.jsindex.jsserver/ // 后端服务routes/ // 路由models/ // 数据模型app.jspackage.json2. 启动前端应用…...

DDD之上下文映射图(Context Mapping)

领域驱动设计系列文章&#xff0c;点击上方合集↑ 1. 开头 在DDD中&#xff0c;限界上下文与限界上下文之间需要相互集成&#xff0c;这种集成关系在DDD中称为上下文映射&#xff08;Context Mapping&#xff09;&#xff0c;也就是子域与子域之间的集成关系。 所以首先我们…...

CountDownLatch的原理

使用CountDownLatch可以实现等待多个线程执行完毕的功能&#xff0c;实现线程之间的协调&#xff0c;让它们按照我们期望的顺序执行&#xff0c;从而避免了可能出现的并发问题。 CountDownLatch是如何实现主线程等待子线程全部结束的呢&#xff1f; 代码用例 这里我们使用一段…...

Java新特性Stream流详解

一、概述 Stream流是Java 8 API添加的一个新的抽象&#xff0c;以一种声明性方式处理数据集合&#xff08;侧重对于源数据计算能力的封装&#xff0c;并且支持序列与并行两种操作方式&#xff09;。 Stream流是对集合&#xff08;Collection&#xff09;对象功能的增强&#xf…...

关于VScode中一些常用的快捷操作!

vscode CTRLO&#xff1a;打开文件夹以开始工作 先CTRLK 再CTRLO&#xff1a;打开文件夹以开始工作 如何选择workspace&#xff1a;file → open folder→选目标文件夹【当前工作区选择会影响代码是否能运行】 如何打开终端&#xff1a;View → terminal debug看不到变化历史&…...

Django 使用Mysql数据库

目录 Django 使用Mysql数据库本地安装Mysql数据服务安装好Pymysql服务Django配置数据库迁移各种报错无法找到mysqlclient数据库拒绝连接 Django 使用Mysql数据库 本地安装Mysql数据服务 安装好Pymysql服务 python3 -m pip install PyMySQL官方文档介绍 Django配置 官网文档 …...

js继承的几种方式(原型链继承、构造函数继承、组合式继承、寄生组合式继承、ES6的Class类继承)

1.原型链继承 实现原理&#xff1a;子类的原型指向父类实例。子类在自身实例上找不到属性和方法时去它父类实例&#xff08;父类实例和实例的原型对象&#xff09;上查找&#xff0c;从而实现对父类属性和方法的继承 缺点&#xff1a; 子类创建时不能传参&#xff08;即没有…...

AnyTransition/过渡动画, MatchedGeometryEffect/匹配几何动画效果 的使用

1. AnyTransition 过渡动画效果 1.1 创建过度动画案例 AnyTransitionBootcamp.swift import SwiftUI/// 旋转修饰 View struct RotateViewModifier :ViewModifier{let rotation: Doublefunc body(content: Content) -> some View {content.rotationEffect(Angle(degrees: r…...

mac版postman升级后数据恢复办法

postman升级了一下&#xff0c;所有的collections都丢失了。 首先在finder里找到这个路径 /Users/{用户名}/Library/Application Support/Postman找到升级之前的的最新的backup.json&#xff0c;然后在postman里import这个文件。 所有升级前的collections都恢复了&#xff0…...

四.镜头知识之放大倍率

四.镜头知识之放大倍率 文章目录 四.镜头知识之放大倍率4.0 前言4.1 镜头的光学放大倍率的计算方法4.2 显示器的电子放大倍率4.2.1 智能硬件产品的显示放大倍率计算案例4.3 系统放大倍率4.4 智能硬件产品的系统放大倍率计算案例4.4 智能硬件产品的系统放大倍率计算案例4.0 前言…...

Jenkins UI 自动化持续化集成测试

一&#xff1a;安装jenkins 环境 在官网下载msi 直接安装即可 二&#xff1a;设置全局变量 设置allure 路径 三&#xff1a;创建项目 1、创建自由风格项目 2、如果项目在本地&#xff0c;且本地服务器是windows &#xff0c;找到Jenkins安装根目录&#xff0c;寻找config…...

vue项目中引入地图的详细教程

第一步&#xff1a;在项目中安装地图插件 npm i amap/amap-jsapi-loader --save 第二步&#xff1a;创建一个容器 添加id属性 &#xff08;因为地图必须使用id 不能使用class&#xff09; <div id"maps"></div> 第三步&#xff1a;给这个容器设置宽…...

MyBatisPlus 多数据源配置

目录 一、mybatis-plus 简介 特性 二、支持数据库&#xff1a; 三、 开发实例 1. 引入依赖&#xff1a; 2. 参数配置application.yml 3. 在 Spring Boot 启动类中添加 MapperScan 注解&#xff0c;扫描 Mapper 文件夹&#xff1a; 4. 编写实体类 User.java&#xff08;此处…...

使用Golang实现HTTP代理突破IP访问限制

引言 在当今互联网时代&#xff0c;网站和服务商为了维护安全性和保护用户隐私&#xff0c;常常会对特定的IP地址进行封锁或限制。但是&#xff0c;有时候我们可能需要访问这些被限制的网站或服务。为了突破这种限制&#xff0c;我们可以使用HTTP代理来隐藏真实的客户端IP地址…...

Iterator和ListIterator的区别是什么?

Iterator 和 ListIterator 都是 Java 集合框架中的迭代器,其中 Iterator 是普遍适用于所有实现了 Iterable 接口的集合类的通用迭代器,而 ListIterator 则是专门用于遍历 List 集合的迭代器,它比 Iterator 更加强大,而且只适用于 List 集合。 以下是 Iterator 和 ListItera…...

大坑-MATLAB图片转存时需注意的点

MATLAB中图片的保存和转存有一个巨大的陷阱&#xff0c;我也是在吃了大亏后发现的&#xff0c;正常情况下&#xff0c;MATLAB跑完实验&#xff0c;生成的图片如下 放大后这样 可以方便修改坐标轴标题&#xff0c;最初我就是因为想修改坐标轴标题才给它放大的&#xff0c;因为…...

基于Lang-Chain(ChatGLM和ChatChat)知识库大语言模型的部署搭建

环境准备 阿里云个人认证后&#xff0c;可免费试用机器学习平台PAI&#xff0c;可提供适合大语言模型环境搭建的高配置服务器。 点击试用阿里云服务器 试用产品选择&#xff1a;选择交互式建模PAI-DSW 适合哪些场景 文章/知识库/帮助文档等的检索基于现有知识库实现问答… …...

个人轻博客PHP开源系统/溯雪Sxlog轻博客源码/洁干净轻/占内存极低/php源码

源码简介&#xff1a; 溯雪(sxlog)它是一款很简洁越低内存的轻博客程序&#xff0c;整个程序包不到200KB&#xff0c;占内存极小&#xff0c;比一张照片都要小很多。简洁高效&#xff0c;占用空间内存极小&#xff0c;而且它不依赖任何数据库&#xff0c;不依赖富文本编辑器&a…...

2.Vue-从零开始搭建一个vue项目

题记 从零开始搭建一个vue项目&#xff0c;以下是操作的全过程。 安装Vue CLI脚手架 打开终端&#xff0c;运行以下命令全局安装Vue CLI脚手架&#xff1a; npm install -g vue/cli 查看 Vue CLI脚手架版本&#xff1a; vue -V 注意&#xff1a;查看vue版本的命令不是vue -V&a…...

快速构建代理应对

今天我要和大家分享一个解决反爬策略升级问题的方法&#xff0c;那就是快速构建代理池。如果您是一位爬虫开发人员&#xff0c;一定深知反爬策略的烦恼。但是&#xff0c;通过构建代理池&#xff0c;您可以轻松地应对反爬策略的升级&#xff0c;让您的爬虫持续高效运行。接下来…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

UnsatisfiedLinkError 在对接硬件设备中&#xff0c;我们会遇到使用 java 调用 dll文件 的情况&#xff0c;此时大概率出现UnsatisfiedLinkError链接错误&#xff0c;原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用&#xff0c;结果 dll 未实现 JNI 协…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型&#xff08;Primitive&#xff09; 和 对象类型&#xff08;Object&#xff09; 两大类&#xff0c;共 8 种&#xff08;ES11&#xff09;&#xff1a; 一、原始类型&#xff08;7种&#xff09; 1. undefined 定…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...

git: early EOF

macOS报错&#xff1a; Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...