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

基于Java+vue+MySQL实现(Web)疫情上报系统

疫情上报系统

一、项目需求

  • 通过在线网络,及时掌握学生每日健康状况。
  • 解决传统健康信息上报问题。传统上报,复杂繁琐,上报信息不能及时汇总,异常信息不能及时传达,效率低下。
  • 预防新冠疫情,能够对异常信息及时排除、早发现、早治疗、早隔离、早诊断。

二、项目功能

学生端:

  • 用户登录
  • 信息上报

职工端:

  • 信息查看
  • 提醒上报 [未开发]
  • 人员管理 [增删改未开发]
  • 名单录入
  • 报单导出

管理员端:[未开发]

  • 对职工的管理功能
  • ...

三、概要设计

1. 学生端

手机或电脑登录上报网址,进行信息上报。

学生端流程:

2. 职工端

项目的重点设计主要是在职工端,职工端涉及的功能模块也比较多。因为要完成对学生信息的录入,上报信息的管理,以及异常信息的处理。

功能模块图如下

3. 数据库表结构设计

初步设计

  • 上报信息表(report_record):存储学生登记信息。
  • 学生信息表(student):记录学生基本信息,默认学号即为学生的账号,不再为学生建立账户信息。(不存在注册操作,职工导入学生名单后,账户即生效!)
  • 职工表(staff):存储职工基本信息,学生的管理员。
  • 院系表(department):存储部门信息。
  • 平台账号信息表(local_auth):记录用户密码账号等信息。(学生存在默认账号,职工账号记录需要存在其中,并且存在相应的权限字段,用以区分是否为 super_admin)

四、详细设计

1. 前台(学生端)

  • 登录模块
    学生使用学号进行登录,登录成功,跳转至登记信息页面;否则,重新登录。
  • 信息登记
    学生登录成功后,登记页面有显示学生的基本信息,包括学号部门等,当然学生可以对自己的班级进行选择,比如调班了不属于该班级了(情况很少,一般不建议改动)。学生填报完所有带有红色*星标的字段信息之后,方可提交,否则提交失败,若提交成功后,会给予成功提示!
    若用户重复上报,最后一次的上报信息会覆盖前一次的上报信息或者只允许用户上报一次(使用拦截器解决用户重复上报问题和未登录就访问上报网址等问题)。

2. 后台(职工 | 管理员)

  • 登录模块
    职工端利用超级管理员下发的账号进行登录,该账号关联了职工的基本信息,登录成功后跳转至后台首页。
  • 后台首页
    • 部门上报信息概览
      展示职工所属部门今日上报情况,已上报、未上报、体温异常等信息。
    • 班级上报信息概览
      列出职工所在部门下所有班级的上报情况,并以进度条的形式展示当前班级的上报进度。职工仅可对自己的班级进行点击查看上报情况,不允许查看其他班级的详细上报情况。
  • 学生端
    • 上报信息
      • 信息查看:职工可查看所管理班级的上报情况,并支持分页查询。
      • 上报通知:职工可对未上报的学生进行通知(发送邮件信息、或者发送短信息)
      • 信息导出:导出指定班级下的今日上报信息。
    • 人员管理
      • 增删改查:人员的增删改查基本操作,以对话框的形式进行设计。
      • 名单录入:职工可对学生名单为空的班级进行录入,多次录入的判断。
  • 管理员
    • 未开发

3. 数据库详细设计

刚开始初步设计的表结构和实体对开发不是那么有利,刚开始单独几个表单单几个字段没多大用处,随着项目集成越来越多的功能,之前的表结构字段不得不进行改造,截止到现在,表结构暂且不是一个绊脚石,各个字段都各有用处。

表结构展示

1)department 表

2)grade 表

3)student 表

4)staff 表

5)report_record 表

6)local_auth 表

五、编程实现

1. 环境搭建

maven 构建项目添加 SSH 框架所需依赖,添加每一层相关的配置文件,主要有 struts.xml、applicationContext.xml、hibernate.cfg.xml,如果配置了连接池、日志等还需要添加相应的配置,结合自己项目所需。每一层相关的配置文件可以借助 IDE 实现配置。(如果导入别人的项目,可以通过左上角的加号对项目进行配置)

2. Spring 集成 struts2 和 hibernate

hibernate:applicationContext 中可以对 hibernate 进行统一配置,可以将.hbm.xml 映射文件配置到 applicationContext 中,事务管理,将 hibernate 的事务交于 Spring,本项目中采用的是编程式事务控制,通过@Transactional 注解来实现的事务管理,这其中有很多坑,详情见项目总结。

struts2:applicationContext 中并没有见 struts2 相关的配置,难道不需要集成 struts 不需要配置?其实环境搭建的时候导入了 struts2-spring-plugin-2.2.1.1.jar,这个 jar 包就实现了 Spring 和 Struts2 的整合,以后可以直接在 aciton 层实现属性注入,前提是必须在 web.xml 中加载了 Spring 的配置。

<!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app><display-name>Archetype Created Web Application</display-name><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></context-param><filter><filter-name>struts2</filter-name><filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class></filter><filter-mapping><filter-name>struts2</filter-name><url-pattern>/*</url-pattern></filter-mapping><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><welcome-file-list><welcome-file>index.html</welcome-file></welcome-file-list></web-app>

3. 功能的实现

通过借助 struts2 的 action,hibernate 的映射和关联,Spring 的 DI 和 AOP,实现业务需求。

项目总结

一、项目技术栈

  • 前端
    HTML、CSS、JavaScript、jQuery、Bootstrap、vue
  • 后端(Java)
    struts2、Spring、hibernate、druid、log4j、EasyExce、MySQL、Tomcat

二、项目开发工具

  • maven
    构建项目,管理项目所需依赖。
  • Git
    版本控制。
  • gitee
    在 gitee 上团队协作,实现代码远程托管。

三、Git 版本控制

1.git push rejected

远程仓库代码版本领先于本地仓库,本地落后于一个或者若干个版本;比如 A 写完代码之后 push 到了仓库,B 在 A 写完之后,没有 merge 就 push 了,这时会被拒绝。解决方法,先 pull merge 之后在进行 push 即可。

2. 代码覆盖问题

Git 强制拉去远程仓库导致的代码覆盖,Git 冲突没有解决导致的代码覆盖(较常见)。所以说不要强制拉去或者不解决冲突。

3. Git 冲突*

Git 冲突的产生:对两个或多个分支已经提交的分支的相同文件相同位置的不同操作进行了合并

解决:

1)在修改文件之前先 merge 或者更新一下本地 master。

2)有冲突手动解决冲突。

四、hibernate 相关

1. Spring 集成 hibernate 实现事务控制

  • hibernate 更新数据没反应
    hibernate 更新数据无反应,因为 hibernate 默认存在缓存,更新默认都是更新缓存中的数据并不会直接写入数据库,可以使用 session.flush 将缓存清空写入。
  • org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread 不能获得同步的事务 session
    原因:
    • SessionFactory 的 getCurrentSession 并不能保证在没有当前 Session 的情况下会自动创建一个新的,这取决于 CurrentSessionContext 的实现,而在 Spring 提供的 CurrentSessionContext 的实现 SpringSessionContext 中,会在开始事务之前通过 AOP 的方式为当前线程创建 Session,此时调用 getCurrentSession()将得到正确结果。当 Hibernate 与 Spring 集成时,将使用该 SessionContext,故此时调用 getCurrentSession()的效果完全依赖于 SpringSessionContext 的实现。(hibernate 的 session 是从 Spring 上下文中获取,上下文中有则拿过来为己所用,否则抛出异常)【注:service 层类上必须添加相应的事务注解,以确保当前 session 能被 Spring 所管理】
    • 在不使用 Spring 的情况下使用 Hibernate,需要在 Hibernate 配置类中设置 current_session_context_class 为 thread,也即使用了 ThreadLocalSessionContext,那么我们在调用 getCurrentSession()时,如果当前线程没有 Session 存在,则会创建一个绑定到当前线程。
    • 在 Spring 中使用 Hibernate,如果我们配置了 TransactionManager,那么我们就不应该调用 SessionFactory 的 openSession()来获得 Sessioin,因为这样获得的 Session 并没有被事务管理。

2.  懒加载异常 LazyInitializationException

懒加载:hibernate 配置对象关联时一对多多对多时,对关联对象采取的一种加载策略。

前台使用 JSON 和后台懒加载的数据进行交互时带来的异常:

## 异常信息
org.apache.struts2.json.JSONException: org.apache.struts2.json.JSONException: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: ncov.model.Department.grades, could not initialize proxy - no Session

1)~~JSONException,因为 hibernate 懒加载获得的是代理对象(session.load 方法),,当向前台传递了这个代理对象的 JSON 数据时会报异常(空指针...),因为对象在转 JSON 时会调用 get 方法,而代理对象是没有 get 方法的。~~说法存在错误,不是这里的原因!

具体原因如下:

  1. Hibernate 允许对关联对象、属性进行延迟加载,但是必须保证延迟加载的操作限于同一个 Hibernate Session 范围之内进行。如果 Service 层返回一个启用了延迟加载功能的领域对象给 Web 层,当 Web 层访问到那些需要延迟加载的数据时,由于加载领域对象的 Hibernate Session 已经关闭,这些导致延迟加载数据的访问异常。而 Spring 为我们提供的 OpenSessionInViewFilter 过滤器为我们很好的解决了这个问题。OpenSessionInViewFilter 的主要功能是使每个请求过程绑定一个 Hibernate Session,即使最初的事务已经完成了,也可以在 Web 层进行延迟加载的操作。OpenSessionInViewFilter 过滤器将 Hibernate Session 绑定到请求线程中,它将自动被 Spring 的事务管理器探测到。所以 OpenSessionInViewFilter 适用于 Service
  2. 延迟初始化错误是运用 Hibernate 开发项目时最常见的错误。如果对一个类或者集合配置了延迟检索策略,那么必须当代理类实例或代理集合处于持久化状态(即处于 Session 范围内)时,才能初始化它。如果在游离状态时才初始化它,就会产生延迟初始化错误。

总结:在 session 关闭时,调用了获取关联对象的方法。

解决方案:LazyInitializationException 多种配置方案。

个人解决方法:取消懒加载机制,那我设置懒加载有何用!因为我暂时不用到这些数据才设置了懒加载,又让我及时加载,对于我来说,不可取!在懒加载的对象上添加@JSON(serializable = flase)注解,含义就是对象转 JSON 时,添加该注解的属性不会被序列化即不会将其转化为 JSON,对于任何请求来说这个是绝对的,如果这样,那么当某个前台功能用到这个数据时却获取不到,这也不行。我采取了下面这种解决方案, 如果前台需要该 JOSN 格式的对象数据,那么在 service 层手动调用该对象关联的对象方法,获得关联对象,目的获取真实的关联对象,这样在转 JSON 时就不会存在代理对象了;如果不需要,那么将该对象的关联对象设置为 null,断开关联。(上面的解决方法不合常规,这里仅仅为了记录一下当初在没有弄明白原理时,所采取的方案。)

注意点:

为什么在 service 层调用相关联的对象方法?如果 Web 层调用会出现 session closed... 的异常信息,因为@Transactional 事务配置在 service 层,Web 层不在管理范围,所以说 Web 层再次调用相关联的对象方法时,session 已经关闭。

3. hibernate 一对多多对多的关联

通过设置对象之间的关联,可以进行级联操作,级联查询就很常用,当我对 department 进行查询时,结合懒加载设置在需要的时候去加载数据,调用 department 属性方法就会得到部门下的 grade 和 staff 实例。

【注】student 关联 reportrecord 设置加载方式为及时加载,因为 EasyExcel 处理数据已经脱离 Spring 和 Web 的范围,如果不是及时加载会出现数据取不到,跑出 Converter 异常等信息。

五、Java Excel 小白式操作

1. EasyExcel

官网 语雀也有文档,当初是看着语雀学习的,上手挺简单的,下面列举的就是刚开始使用出现的问题。

1)asm.jar、cglib 包版本冲突【jar 冲突的原因关注这两个】

2)测试 EasyExcel 读取文件并向 DB 中存储数据的时候,突然存储到一半,就一直在那转个不停,也不会再向数据库存储记录。

原因:

1)从池中的的连接都已经用完,没有可以利用的连接,可以设置连接池的属性,来增大池中的连接数量。

2)如果不设置连接池属性,可以通过增大每次读取的数量,即 BATCH_SIZE(最先想到的是这一种,当时估摸着是不是池中的连接没有了,才会出现上述不会在运行但不会存储记录的情况)。数据量大的情况下,这种设置增加了内存的压力。

六、vue 总结

本次开发前端框架用到的是 vue,感觉用它如虎添翼,比 jQuery 操作 DOM 元素方便多去了,双向绑定,MVVM(Model-View-ViewModel),初次上手,感觉也踩了很多坑。

1)vue 死循环问题

You may have an infinite update loop in a component render function.

出现上述情况的原因主要是因为,for 循环判断条件中调用了某个函数,函数内部又对 vue 实例中的属性值进行了修改,导致 vue 重新 render,从而 dead loop.

2)this 对象问题

我们通常会为每个页面定义一个 vue 实例,this 值通常也为 vue,但是比如我用了 axios 发送请求获取响应的时候,这时候的 this 不在是 vue 实例而是一个 window 对象,还有就是 list.forEach(function(item, index) {...})forEachfunction 中 this 也不再是 vue 实例,开发中常常这样定义 let _this = this 保存 vue 实例!从而在其他函数内部使用 vue 实例。

3)分页数量计算出现小数时引发的数组下表越界。

七、MySQL 定时任务(定时事件)

项目为什么会用到定时任务?

为了统计每日上报数量,如果仔细看表,你会发现 department 和 grade 会有一个 submitted_count 字段,这个字段记录了当日上报的人数,如果第二天进行上报,需要将该字段清零,所以我最先考虑到用定时任务来去做这一个事情。同样如果项目扩展开来,可以用定时任务控制每日表单的填报时间等等。因为对 Java 定时任务不太了解,这里用了 MySQL 的 Event 来处理。

处理方式:

1)将 student 表中的 report_id 外键字段置空后,清空 report_record 表的记录,department、grade 下的 headcount 归 0。

2)将 student 表中的 report_id 外键字段置空,保留 report_record 表中的字段,下次只会更新相应的记录,department、grade 下的 headcount 归 0。

置空 student 表中的 report_id 原因就是 update 或者 insert 就是和 report 建立关联,之后 headcount 才会增一。

这里采取(2)

create EVENT clear_zero
on SCHEDULE EVERY 1 DAY STARTS '2020-06-15 00:00:00'
DO
UPDATE department 
SET submitted_count = 0 
WHEREsubmitted_count != 0;
UPDATE grade 
SET submitted_count = 0 
WHEREsubmitted_count != 0;
UPDATE student 
SET report_id = NULL 
WHEREreport_id IS NOT NULL;

可以利用 navicate 图形化工具创建 event 或者手写 SQL,事件的具体操作,网上都有介绍,这里不再陈述。

八、项目待做

  • 后台登录验证码 EasyCaptcha
  • 后台首页部门下班级概览那地方,所属职工可通过超链接的形式链接到本班的上报信息界面,不属于自己管理的班级不可查看。(拦截器实现)
  • 首页体温异常模块
  • 上报信息展示,感染疑似和正常可以用 HTML 样式加以区分
  • 上报信息的编辑操作:清空上报记录和通知,通知可以以邮件形式或者手机短信息通知。
  • 学生信息的增删改【删除完成 report_record 处理存在问题】
  • 职工信息的信息的个人设置
  • 超级管理员模块的开发
  • 高级管理员指定每个职工所管理的班级,每个班级所属职工就固定了
  • 缓存问题导致的拦截器失效!(缓存严重!待解决)有时候影响正常功能的使用,拦截器不能轻易使用!网址要变化,不然还是有缓存!

项目部署注意点

  • 项目依赖了线上的 vue 库,也就是说如果电脑没有联网的情况下,vue.js 库不会加载成功,导致页面变形或者功能失效。
  • 前端页面用了 vue 和 jQuery,如果利用 vue 的方法去处理事件可能会出现事件失效,原因就是作用域不在 vue 范围内;另外如果项页面中点击事件失效,可能是 jQuery 和 vue 库并存导致的原因,为什么,网上都有有所说,这里不再细说,就是 vue 会重塑 dom 树,之前利用 jQuery 在 dom 节点上添加过的事件都会失效。
  • global.properties 定义了全局属性配置,将数据库的用户名密码配置抽取到了这里面,部署根据自己的 MySQL 进行配置。
http://www.dtcms.com/a/306709.html

相关文章:

  • 架构实战——架构重构内功心法第一式(有的放矢)
  • Effective C++ 条款12:复制对象时勿忘其每一个成分
  • AD里面出现元器件PCB封装不能编辑的情况
  • UE5保姆级新手教程第六章(角色互动)
  • 低成本高可控,TEMU自养号测评的6大核心优势解析
  • 【数据可视化-76】从释永信被查,探索少林寺客流量深度分析:Python + Pyecharts 炫酷大屏可视化(含完整数据和代码)
  • 142页|中型国有企业数字化转型方法论:京东数智化转型解决方案-五化方法论
  • Apache Ignite 集群标识(Cluster ID)和集群标签(Cluster Tag)
  • Python多线程利器:重入锁(RLock)详解——原理、实战与避坑指南
  • 国产音频DA转换芯片DP7361支持192K六通道24位DA转换器
  • AI服务器中,EEPROM有哪些部件使用,需要存储哪些信息?
  • sqli-labs:Less-2关卡详细解析
  • 跨云部署实战:前端、后端 + RSYNC、全栈场景统一落地方案
  • 在macOS上使用VS Code和Clang配置C++开发环境
  • 《解密React key:虚拟DOM Diff中的节点身份锚点》
  • Undo、Redo、Binlog的相爱相杀
  • GIS工程师面试题
  • Java项目:基于SSM框架实现的济南旅游网站管理系统【ssm+B/S架构+源码+数据库+毕业论文+远程部署】
  • 力扣 hot100 Day60
  • Rabbit MQ的消息模式-Java原生代码
  • 发那科机器人P点位置号码自动变更功能为禁用状态
  • 认识ansible(入门)
  • 《嵌入式C语言笔记(十六):字符串搜索、动态内存与函数指针精要》
  • RocketMQ 核心特性解析及与 Kafka区别
  • 思途JSP学习 0730
  • DP-v2.1-mem-clean学习(3.6.7)
  • 片上变化(OCV)
  • 7.Origin2021如何绘制拟合数据图?
  • Python 之抽象方法 @abstractmethod 的理解
  • Day06_C++编程