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

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机&#xff0c;点进去 点进去 查看URL&#xff0c;有 ?fileflag.php说明存在文件包含&#xff0c;原理是php://filter 协议 当它与包含函数结合时&#xff0c;php://filter流会被当作php文件执行。 用php://filter加编码&#xff0c;能让PHP把文件内容…...