当前位置: 首页 > 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;让您的爬虫持续高效运行。接下来…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...