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

2026年除铁器磁选机优选指南

随着工业技术的不断进步&#xff0c;除铁器磁选机在矿山、冶金、化工等行业中的应用越来越广泛。选择一款高效、可靠的除铁器磁选机对于企业来说至关重要。本文将从多个角度分析如何选择适合您的除铁器磁选机&#xff0c;并推荐一个值得信赖的品牌——云海机械。一、了解除铁器…...

手把手教你搞定Elsevier投稿:从LaTeX编译到PDF检查的保姆级避坑指南

手把手教你搞定Elsevier投稿&#xff1a;从LaTeX编译到PDF检查的保姆级避坑指南 第一次用LaTeX向Elsevier投稿的研究者&#xff0c;往往会在文件打包和格式校验环节遭遇"隐形陷阱"。我曾亲眼见证一位博士生在截稿前3小时因PDF乱码而崩溃——问题竟出在一个未被编译的…...

Equalizer APO:Windows系统级音频均衡器的完整使用指南

Equalizer APO&#xff1a;Windows系统级音频均衡器的完整使用指南 【免费下载链接】equalizerapo Equalizer APO mirror 项目地址: https://gitcode.com/gh_mirrors/eq/equalizerapo 你是否曾经因为Windows系统的音频输出平淡无奇而感到困扰&#xff1f;无论是游戏中的…...

别再只用SIFT了!手把手教你用Colmap的RootSIFT和自定义特征提升三维重建精度

别再只用SIFT了&#xff01;手把手教你用Colmap的RootSIFT和自定义特征提升三维重建精度 当你在处理无人机航拍数据时&#xff0c;是否遇到过特征匹配不稳定导致的三维模型断裂&#xff1f;当你在进行文物数字化时&#xff0c;是否被光照变化带来的特征漂移所困扰&#xff1f;这…...

GCC编译参数`-Werror`和`-Wimplicit-fallthrough`详解:如何平衡代码质量与开发效率?

GCC编译参数-Werror与-Wimplicit-fallthrough实战指南&#xff1a;工程化配置与团队协作策略 在C/C项目的持续集成流水线中&#xff0c;开发团队经常面临这样的困境&#xff1a;某个看似无害的代码修改触发了-Wimplicit-fallthrough警告&#xff0c;而由于-Werror的严格设置&am…...

3步完成MOOC课程永久保存:MoocDownloader的离线学习解决方案

3步完成MOOC课程永久保存&#xff1a;MoocDownloader的离线学习解决方案 【免费下载链接】MoocDownloader An MOOC downloader implemented by .NET. 一枚由 .NET 实现的 MOOC 下载器. 项目地址: https://gitcode.com/gh_mirrors/mo/MoocDownloader 你是否曾因网络不稳定…...

【实战指南】龙芯2K1000开发板:从零到一,快速上手全功能测试

1. 龙芯2K1000开发板开箱与硬件组装 第一次拿到迅为iTOP龙芯2K1000开发板时&#xff0c;包装盒里整齐排列的配件让我这个嵌入式老手也眼前一亮。作为国产处理器的代表作&#xff0c;这块开发板确实在硬件配置上下了功夫。我们先来清点标配配件&#xff1a;12V电源适配器、232串…...

从数据标注到模型部署:基于YOLOv8+RT-DETR的车道抛洒物检测保姆级全流程(含labelImg使用教程)

车道抛洒物检测实战&#xff1a;从零构建YOLOv8与RT-DETR融合模型 项目背景与核心价值 高速公路和城市道路上突然出现的抛洒物&#xff08;如碎石、货物残渣、轮胎碎片&#xff09;是引发交通事故的重要隐患。传统人工巡检方式效率低下且成本高昂&#xff0c;而基于深度学习的实…...

QQ音乐解析终极指南:2025年高效免费音乐获取完整解决方案

QQ音乐解析终极指南&#xff1a;2025年高效免费音乐获取完整解决方案 【免费下载链接】MCQTSS_QQMusic QQ音乐解析 项目地址: https://gitcode.com/gh_mirrors/mc/MCQTSS_QQMusic 还在为QQ音乐无法下载心爱歌曲而烦恼吗&#xff1f;想要随时随地畅听高品质音乐却受限于平…...

保姆级教程:用Arduino和三个电感实现智能车归一化循迹(附完整代码与调试心得)

从零搭建智能车循迹系统&#xff1a;Arduino电感归一化实战指南 当你第一次把三个电感传感器排列在智能车前端时&#xff0c;那些不断跳动的模拟值可能会让你感到困惑——左边的电感在金属导线附近显示512&#xff0c;中间的687&#xff0c;右边的突然飙到1023。这些原始数据就…...