javaWeb-SpringBoot微信调查问卷+问卷数据大屏项目
项目效果概览:
项目架构:
获取文件模板,前端就会展示问卷的列表,我们就可以选择选项,结果就会同步到我们的后端,通过后端把统计结果发生到前端,完成整个流程.
git仓库地址:
目录标题
- 项目效果概览:
- 项目架构:
- git仓库地址:
- 1.基础准备工作
- 1.1lombok插件
- 1.2maven依赖配置
- 1.3 接口设计
- 1.4模块式开发
- 1.5common公共类
- 1.5.1BaseResponseVO:实现的是公共返回值
- 15.2CorsFilter:解决跨域问题
- 1.6utils工具类
- 1.7conf配置读取类
- 1.7.1配置application.yml文件
- 1.7.2做一个测试的模板
- 2.微信调查问卷模板配置
- 3.业务层实现(业务层实现在service包下)
- 3.1接口WechatTemplateService,主要作用是提供controller进行调取的,真正实现方法在接口的实现类中
- 3.2接口WechatTemplateService的实现类,通过此类实现接口中定义的方法
- 4.表现层controller实现
- 5.程序业务测试
- 6.Kafka Producer集成
- 7.HTTPS的支持(因为微信小程序要求必须是HTTPS)
- 7.1CA证书申请
- 7.2域名绑定
- 8.集成SSL证书
- 9.阿里云部署后端
- 10.编译部署
- 11.完整项目代码git仓库地址
- 12.项目后续扩展
- 12.1BigData实现
1.基础准备工作
1.1lombok插件
lomlok的作用主要是简化代码开发
1.2maven依赖配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.5.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.imooc.jiangzh</groupId><artifactId>kafka-study</artifactId><version>0.0.1-SNAPSHOT</version><name>kafka-study</name><description>微信调查问卷</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><!--springBoot依赖两个---><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>4.1.1</version></dependency><!--kafka相关依赖两个--><dependency><groupId>org.apache.kafka</groupId><artifactId>kafka-clients</artifactId><version>2.4.0</version></dependency><dependency><groupId>org.apache.kafka</groupId><artifactId>kafka-streams</artifactId><version>2.4.0</version></dependency><!-- lombok依赖 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>28.2-jre</version></dependency><!-- fastjson依赖 --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.68</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
1.3 接口设计
1.4模块式开发
成品样式:
1.5common公共类
1.5.1BaseResponseVO:实现的是公共返回值
用泛型去做枚举,当需要真实返回值的时候按照枚举类型进行传入就可以,当不需返回值的时候,只有RequestId
package com.yuge.wechat.questionnaire.common;import java.util.UUID;
import lombok.Data;/*** @description : 公共返回对象**/
@Data
public class BaseResponseVO<M> {private String requestId;private M result;public static<M> BaseResponseVO success(){BaseResponseVO baseResponseVO = new BaseResponseVO();baseResponseVO.setRequestId(getRequestId());return baseResponseVO;}public static<M> BaseResponseVO success(M result){BaseResponseVO baseResponseVO = new BaseResponseVO();baseResponseVO.setRequestId(getRequestId());baseResponseVO.setResult(result);return baseResponseVO;}private static String getRequestId(){return UUID.randomUUID().toString();}}
15.2CorsFilter:解决跨域问题
package com.yuge.wechat.questionnaire.common;import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Configuration;/*** @description : 跨域问题解决**/
@WebFilter(filterName = "CorsFilter")
@Configuration
public class CorsFilter implements Filter {@Overridepublic void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {HttpServletResponse response = (HttpServletResponse) res;response.setHeader("Access-Control-Allow-Origin","*");response.setHeader("Access-Control-Allow-Credentials", "true");response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");response.setHeader("Access-Control-Max-Age", "3600");response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");chain.doFilter(req, res);}
}
1.6utils工具类
package com.yuge.wechat.questionnaire.utils;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Optional;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;/*** @description : 文件工具类* 给一个路径filePath,返回路径下内容,重载了多种返回类型:string,JSONObject,JSONArray**/
@Slf4j
public class FileUtils {public static String readFile(String filePath) throws IOException {@CleanupBufferedReader reader = new BufferedReader(new FileReader(new File(filePath)));String lineStr = "";StringBuffer stringBuffer = new StringBuffer();while ((lineStr = reader.readLine()) != null) {stringBuffer.append(lineStr);}return stringBuffer.toString();}public static Optional<JSONObject> readFile2JsonObject(String filePath){try {String fileContent = readFile(filePath);log.info("readFile2Json fileContent: [{}]" , fileContent);return Optional.ofNullable(JSON.parseObject(fileContent));} catch (IOException e) {e.printStackTrace();}return Optional.empty();}public static Optional<JSONArray> readFile2JsonArray(String filePath){try {String fileContent = readFile(filePath);log.info("readFile2Json fileContent: [{}]" , fileContent);return Optional.ofNullable(JSON.parseArray(fileContent));} catch (IOException e) {e.printStackTrace();}return Optional.empty();}}
1.7conf配置读取类
package com.yuge.wechat.questionnaire.conf;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;import java.util.List;@Data
@Configuration
@ConfigurationProperties(prefix = "template")
public class WechatTemplateProperties {private List<WetchTemplate> templates;private int templateResultType; //0-文件夹 1-数据库private String templateResultFilePath;//结果文件路径 @Datapublic static class WetchTemplate{private String templateId; //模板编号,用来模板对应接口的唯一标识private String templateFilePath;private String active;}
}
1.7.1配置application.yml文件
- 注意:conf类下定义的变量是驼峰命名templateResultType到application需要转成tempalte_result_type
server:port: 8080template:templates:- {"templateId":"1","templateFilePath":"C:/user/MyCode/wechat-questionnaire/src/main/resources/template/template.json","active":true}- {"templateId":"2","templateFilePath":"C:/user/MyCode/wechat-questionnaire/src/main/resources/template/template.json","active":false}template_result_type: 0template_result_filePath: "C:/user/MyCode/wechat-questionnaire/src/main/resources/template/templateRestlt.json"
注意事项:路径是用反斜杠的,而反斜杠在java中是转义符所有把把反斜杠换成/才可以
这一个json是由多个数组组成的,一个数组就一个文件的题目和选项
前端展示的时候他会通过接口调这个文件的内容,文件是什么内容他就会展示什么内容
1.7.2做一个测试的模板
[{ "questionId": "1", //问题编号"question": "今天几号", //问题内容"answer": "", //默认答案"options": [ //选项{"label": "1 号", "value": "A"},{"label": "2 号", "value": "B"},{"label": "3 号", "value": "C"},{"label": "4 号", "value": "D"}
]},{"questionId": "2","question": "你喜爱的颜色","answer": "","options": [{"label": "红色", "value": "A"},{"label": "黄色", "value": "B"},{"label": "绿色", "value": "C"},{"label": "紫色", "value": "D"}
]}
]
{ "templateId": "001", //模板编号"totalNumber": "102", //有多少人作答"statistics": [ { //针对这个templateId我们统计的结果是什么"questionId": "1","question": "今天几号","answers": [
{"label": "A", "value": 10}, //选a的10人 ,选b的50人,选c的12人,选d的17人
{"label": "B", "value": 50},
{"label": "C", "value": 12},
{"label": "D", "value": 17}
]
}, {"questionId": "2","question": "你喜爱的颜色","answers": [ {"label": "A", "value": 12},{"label": "B", "value": 52},{"label": "C", "value": 17},{"label": "D", "value": 17} ]
}
]
}
一个存储模板一个存储模板的结果
2.微信调查问卷模板配置
3.业务层实现(业务层实现在service包下)
3.1接口WechatTemplateService,主要作用是提供controller进行调取的,真正实现方法在接口的实现类中
package com.yuge.wechat.questionnaire.service;import com.alibaba.fastjson.JSONObject;
import com.yuge.wechat.questionnaire.conf.WechatTemplateProperties;public interface WechatTemplateservice {//前端获取统计的模板 获取active为true的模板WechatTemplateProperties.WetchTemplate getWeChatQuestionnaireTemplate();//前端返回调查问卷结果数据到后端void reportTheResultsOfTheQuestionnaire(JSONObject resultsData);//后端把统计结果数据发送给前端JSONObject questionnaireStatistics(String templateId);}
3.2接口WechatTemplateService的实现类,通过此类实现接口中定义的方法
package com.yuge.wechat.questionnaire.service;import com.alibaba.fastjson.JSONObject;
import com.yuge.wechat.questionnaire.conf.WechatTemplateProperties;
import com.yuge.wechat.questionnaire.utils.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Optional;@Slf4j //lombok提供的日志
@Service
public class WechatTemplateServiceImpl implements WechatTemplateservice {@AutowiredWechatTemplateProperties properties;/*** 前端向后端获取微信调查问卷为active模板* @return*/@Overridepublic WechatTemplateProperties.WetchTemplate getWeChatQuestionnaireTemplate() {List<WechatTemplateProperties.WetchTemplate> templates = properties.getTemplates();Optional<WechatTemplateProperties.WetchTemplate> wetchTemplate = templates.stream().filter((template) -> template.isActive()).findFirst();return wetchTemplate.isPresent()? wetchTemplate.get():null;}/*** 前端问卷结果返回后端* @param resultsData*/@Overridepublic void reportTheResultsOfTheQuestionnaire(JSONObject resultsData) {//kafka Producer 将数据推倒topiclog.info("reportTheResultsOfTheQuestionnaire:[{}]",resultsData);}/*** 后端前前端发送调查问卷统计结果* @param templateId* @return*/@Overridepublic JSONObject questionnaireStatistics(String templateId) {if (templateId=="0"){ //0就文件获取return FileUtils.readFile2JsonObject(properties.getTemplateResultFilePath()).get();}else{//其他数据源获取return null;}}
}
4.表现层controller实现
实现的是三个接口逻辑
package com.yuge.wechat.questionnaire.controller;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yuge.wechat.questionnaire.common.BaseResponseVO;
import com.yuge.wechat.questionnaire.conf.WechatTemplateProperties;
import com.yuge.wechat.questionnaire.service.WechatTemplateservice;
import com.yuge.wechat.questionnaire.utils.FileUtils;
import org.apache.kafka.common.protocol.types.Field;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;@Controller
@RequestMapping("/v1")
public class WechatTemplateController {@AutowiredWechatTemplateservice wechatTemplateservice;@AutowiredWechatTemplateProperties properties;/*** 获取调查问卷模板的数据(前端获取一个问卷内容,供客户来填写)*/@RequestMapping(value = "/getTheQuestionnaireTemplate",method = RequestMethod.GET)public BaseResponseVO getTheQuestionnaireTemplate(){WechatTemplateProperties.WetchTemplate wetchTemplate = wechatTemplateservice.getWeChatQuestionnaireTemplate();HashMap<String, Object> map = new HashMap<>();map.put("templateId",wetchTemplate.getTemplateId());map.put("template", FileUtils.readFile2JsonArray(properties.getTemplateResultFilePath()));return BaseResponseVO.success(map);}/*** 返回到后端的问卷填写数据,*/@RequestMapping(value = "/returnQuestionnaireResults",method = RequestMethod.POST)public BaseResponseVO returnQuestionnaireResults(@RequestBody String resultData){wechatTemplateservice.reportTheResultsOfTheQuestionnaire(JSON.parseObject(resultData));return BaseResponseVO.success();}/*** 返回数据的统计结果,允许前端传入模板编号*/@RequestMapping(value = "/getQuestionnaireStatistics",method = RequestMethod.GET)public BaseResponseVO getQuestionnaireStatistics(@RequestParam(value="templateId",required = false) String templateId){JSONObject statistics = wechatTemplateservice.questionnaireStatistics(templateId);return BaseResponseVO.success(statistics);}
}
5.程序业务测试
-- 查询模板信息
curl -XGET http://localhost:8080/v1/template-- 查询模板统计结果
curl -XGET http://localhost:8080/v1/template/result-- 传入调查问卷结果
curl -XPOST -H "Content-Type:application/json; charset=UTF-8" http://localhost:8080/v1/template/report -d \
'{templateId:"001",result:[{"questionId":"1","question":"今天几号","answer":"A"},{"questionId":"2","question":"你喜爱的颜色","answer":"B"}]
}'
netstat -ano | findstr 443
6.Kafka Producer集成
package com.imooc.jiangzh.kafka.wechat.conf;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;@Data
@Configuration
@ConfigurationProperties(prefix = "wechat.kafka")
public class KafkaProperties {private String bootstrapServers;private String acksConfig;private String retriesConfig;private String batchSizeConfig;private String lingerMsConfig;private String bufferMemoryConfig;private String keySerializerClassConfig;private String valueSerializerClassConfig;}
package com.imooc.jiangzh.kafka.wechat.conf;import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.Properties;@Configuration
public class KafkaConf {@Autowiredprivate KafkaProperties kafkaProperties;@Bean//增加@Bean注释:依赖spring提供的上下文,来做一个单例模式,这样我们所以的线程都是共享同一个kafkaProducerpublic Producer kafkaProducer(){Properties properties = new Properties();properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaProperties.getBootstrapServers());properties.put(ProducerConfig.ACKS_CONFIG, kafkaProperties.getAcksConfig());properties.put(ProducerConfig.RETRIES_CONFIG,kafkaProperties.getRetriesConfig());properties.put(ProducerConfig.BATCH_SIZE_CONFIG,kafkaProperties.getBatchSizeConfig());properties.put(ProducerConfig.LINGER_MS_CONFIG,kafkaProperties.getLingerMsConfig());properties.put(ProducerConfig.BUFFER_MEMORY_CONFIG,kafkaProperties.getBufferMemoryConfig());properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,kafkaProperties.getKeySerializerClassConfig());properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,kafkaProperties.getValueSerializerClassConfig());// Producer的主对象Producer<String,String> producer = new KafkaProducer<>(properties);return producer;}
}
7.HTTPS的支持(因为微信小程序要求必须是HTTPS)
7.1CA证书申请
7.2域名绑定
8.集成SSL证书
9.阿里云部署后端
10.编译部署
11.完整项目代码git仓库地址
12.项目后续扩展
上述只是简单的实现了微信小程序的调查问卷功能:
后期项目迭代增加需求:
1.通过mybaits依赖增加mysql数据库支持
2.增加大数据分析大屏数据展示
12.1BigData实现
我们通过kafkaProducer把数据发送到topic上面,但是数据并未做任何分析和展示,后期我们需要做一个数据大屏,来统计分析文件结果,并直观展示.
- 架构:kafkaProducer->consumer->hbase->sparkSQL->hbase->Kylin(数据展示)
javaWeb-SpringBoot微信调查问卷+问卷数据大屏项目相关推荐
- 数据大屏项目Vue+DataV+Echarts(附源码)
一.项目描述 1 前端项目 1.1 项目简介 一个基于 Vue.datav.Echart 框架的 " 数据大屏项目 ",通过 vue 组件实现数据动态刷新渲染,内部图表可实现自由替 ...
- 工资8000以下的程序员注意了:《零coding数据大屏实战宝典.pdf》
马云曾说:"整个世界将变成数据,这还只是数据时代的开始.新浪潮即将来临,很多就业机会将被夺走.有些人会赶上潮流,变得富有和成功.但是对那些落后的人,未来将是痛苦的. 大数据从2013年一路发 ...
- 爆肝十小时,为你总结出最全的数据大屏适配屏幕方案
前言 近期公司投放在展厅大屏中演示的大数据页面,出现了文字.图表.表格等多类组件显示错乱的情况,大部分原因还是适配问题. 我们做数据大屏时,因为显示器尺寸不同,会导致展示的时候有留白区域,效果不好,所 ...
- Springboot+Vue+Echarts实现51job大数据岗位分析数据大屏
效果图: 后端代码: 前端代码: 前后端分离开发,适合当大数据数据大屏大作业,需要源码请私信!
- 用户数据销售额分析动态大屏看板+大屏数据可视化图表组件(折线图+圆柱图+散点图+饼图+漏斗图+雷达图+水位图)+智能web端高保真大数据动态可视化大屏看板+中国动态地图+智慧电商实时动态数据大屏看板
作品内容:用户数据销售额分析动态大屏看板+大屏数据可视化图表组件(折线图+圆柱图+散点图+饼图+漏斗图+雷达图+水位图)+web端高保真大数据动态可视化大屏看板+中国动态地图+电商实时动态数据大屏看板 ...
- web大屏展示用到的组件_从零开始设计数据大屏—基于Vue
为什么要做数据大屏? 现如今的大数据逐渐发挥出了它的力量,并无形的改变着我们的生活.但大数据在不是从事技术开发的人来说没有很明显的感受,很多人对大数据的概念只是停留在每年网易云音乐对个人听歌的汇总上. ...
- PywebIO 轻松制作一个数据大屏,代码只需100行
今天我给大家分享一个制作数据大屏的工具,非常的好用,100行的Python代码就可以制作出来一个完整的数据大屏,并且代码的逻辑非常容易理解. PywebIO介绍 Python当中的PywebIO模块可 ...
- 数据大屏可视化2-超全的基础图形模板(基础模版)
内容整理于网络,因为忘了之前是从那几篇文章中整理的了,所以转载的连接不知道填啥,如果作者有看到的话,可以联系下我,谢谢 注意:所有带有import random的都是生成随机数展示的,如果有需要研究对 ...
- 数聚易视重磅推出,助力企业级数据大屏可视化
数字化转型趋势下,以大屏为主要载体的数据可视化需求日益增加.大屏给人以震撼的视觉冲击,呈现直观丰富的信息,有效帮助管理或业务人员决策.判断.发现问题.诊断问题,已经成为数字化管理中不可或缺的场景之一. ...
最新文章
- 转换字符串中汉字为其拼音缩写(C#)
- 切歌请按3或4!我把树莓派装进了旋转电话里,现在它成了一部MP3
- redmine3.3.1安装与常用插件安装
- 第拾壹章學習 Lisp 3rd Edition, Winston Horn
- Spark常规性能调优三:并行度调节
- python yield用法举例说明
- 作为一名通信老司机,我是如何看待翼龙通信无人机救灾的?
- java class获取type_java – 获取Class [Runtime-Type Token]的实例
- CBNetV2论文的译读笔记
- commons,jsoup,htmlunit,jackson,nekohtml,Object,xalan,xercesImpl,beanutils,lang3,httpclient,jar包下载
- python用wordcloud简单词云_用Python和WordCloud绘制词云的实现方法(内附让字体清晰的秘笈)...
- ubuntu14.04 sougou输入法, qtcreator适配sougou输入法
- [ 读书笔记 ] 1 -《 程序员修炼之道 - 通向务实的最高境界 (第2版)》
- 9gag for android,GitHub - Mixiaoxiao/9GAG: 9GAG-Android (unofficial), Android Design.
- 抖音只能上下滑动吗_仿抖音上下滑动分页视频
- 如何查询快递单号物流
- iOS app 的开发要准备哪些图标图片?
- pytorch整理(三)
- python控制画笔尺寸_Python turtle库的画笔控制说明
- 积微——荀子《强国篇》,给每个职场人士推荐
热门文章
- stat() /root/xxx/index.html failed (13: Permission denied)
- SVN(subversion )服务端和客户端的下载安装使用
- 潮流话机直接对接讯时FXO
- 一文带你深入浅出C语言运算符、表达式和语句
- 鼠标经过文字显示隐藏图片css样式
- 人教版初中计算机教案全本,人教版初中信息技术教案全集
- TileMap插件学习
- Java 2 实用教程(第5版)耿祥义版 习题七
- PC屏幕颜色识别实现鼠标自动点击
- 麒麟安全IPO过会:拟募资6.6亿 第一季营收下降40%