畢業(yè)設計:基于Springboot+Vue+ElementUI實現(xiàn)疫情社區(qū)管理系統(tǒng)
?項目編號:BS-XX-131
前言:
? ? ? ? ?居民所處的社區(qū)管控一直是疫情防控的一線,社區(qū)管控的力度直接決定著全國整個疫情防控的成敗。國家對于疫情的防控可以通過信息化和大數(shù)據(jù)對人的行蹤進行有效的流調(diào),通過信息化技術(shù)的應用大大降低了整體疫情防控的力度和患者排查的難度,但是處于一線的社區(qū)防控工作,在信息化的建設和應用上還是相對比較空白的,目前好多社區(qū)還是通過保安人工記錄和統(tǒng)計社區(qū)人員的流動及相關(guān)信息,在此背景下,希望能夠利用信息化技術(shù),為社區(qū)防控開發(fā)一套管理系統(tǒng),能幫助社區(qū)人員更好的管理社區(qū)居民疫情情況、進入情況,能夠方便的實現(xiàn)對社區(qū)內(nèi)各小區(qū)的人員情況有著更好的管理。本文就基于Springboot框架開發(fā)和實現(xiàn)一個應用于社區(qū)居民疫情防控管理系統(tǒng)的相關(guān)問題進行分析和研究。
一,項目簡介
?本次開發(fā)設計的社區(qū)疫情管理系統(tǒng),主要為一線的社區(qū)人員更好的管理轄區(qū)內(nèi)人員疫情風險信息提供信息化的管理手段。本系統(tǒng)基于Springboot+Vue開發(fā)實現(xiàn)了一個前后端分離的信息化管理系統(tǒng)。系統(tǒng)功能完整,界面簡潔大方。系統(tǒng)用戶主要分為居民用戶和管理員用戶,居民注冊登陸后主要可以在線提交自己的體溫信息、外出信息、行程信息等,管理員用戶主要管理和查看這些基礎的信息數(shù)據(jù)。
? ? 特色:
1.系統(tǒng)利用定時任務每天自動爬取百度的疫情統(tǒng)計數(shù)據(jù)并更新到本地的數(shù)據(jù)庫表中,在本系統(tǒng)中可以查看國內(nèi)的最新疫情數(shù)據(jù)。
2.使用SpringSecutiry權(quán)限管理框架來管理用戶的權(quán)限身份
3.使用前后端分離開發(fā)模式,將前端和后臺有效的分離,通過Axios向后臺代理轉(zhuǎn)發(fā)請求接口
4.使用Jsoup爬蟲來爬取百度的實時疫情數(shù)據(jù),并進行解析,將解析的數(shù)據(jù)保存到mysql數(shù)據(jù)庫中
二,環(huán)境介紹
語言環(huán)境:Java:? jdk1.8
數(shù)據(jù)庫:Mysql: mysql5.7
應用服務器:Tomcat:? tomcat8.5.31
開發(fā)工具:IDEA或eclipse
后臺開發(fā)技術(shù):Springboot+Mybatis-Plus+SpringSecutiry+定時任務Quartz
前端開發(fā)技術(shù):Vue+ElementUI+Axios
三,系統(tǒng)展示
下面展示一下社區(qū)疫情防控系統(tǒng):
前端用戶注冊

登陸

管理主界面

個人每天體溫上報及查詢

外出管理:高風險地區(qū)或體溫異常者無法添加外出信息,也就是無法外出

行程管理

個人信息管理

管理員登陸
體溫管理

外出管理

居民行程管理

社區(qū)和小區(qū)地址管理

用戶管理

異常用戶管理

四,核心代碼展示
爬蟲核心代碼:
package com.gad.epidemicmanage.task;import com.gad.epidemicmanage.common.GlobalConstant;import com.gad.epidemicmanage.pojo.entity.RealTimeData;import com.gad.epidemicmanage.service.IRealTimeDataService;import com.gad.epidemicmanage.common.utils.CommonUtil;import com.gad.epidemicmanage.common.utils.HttpUnitUtil;import lombok.extern.slf4j.Slf4j;import org.jsoup.Jsoup;import org.jsoup.nodes.Document;import org.jsoup.nodes.Element;import org.quartz.DisallowConcurrentExecution;import org.quartz.Job;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;import org.springframework.stereotype.Component;import javax.annotation.Resource;/**
* 獲取國內(nèi)疫情實時數(shù)據(jù)
*/public class RealTimeDataTask implements Job { ? ?
? ?private IRealTimeDataService realTimeDataService; ? ?
? ?public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { ? ? ? ?int i = 0; ? ? ? ?int maxTimes = 5; ? ? ? ?while(i < maxTimes){ ? ? ? ? ? ?String html = HttpUnitUtil.getHtmlPage(GlobalConstant.REAL_TIME_URL); ? ? ? ? ? ?if ("".equals(html)) {
? ? ? ? ? ? ? ?log.error("國內(nèi)實時數(shù)據(jù)獲取頁面失敗"); ? ? ? ? ? ? ? ?return;
? ? ? ? ? ?}else {
? ? ? ? ? ? ? ?log.info("國內(nèi)實時數(shù)據(jù)獲取頁面成功,開始第 "+ (i+1) +" 次分析");
? ? ? ? ? ?} ? ? ? ? ? ?try{ ? ? ? ? ? ? ? ?Document document = Jsoup.parse(html); ? ? ? ? ? ? ? ?//獲取模塊節(jié)點
? ? ? ? ? ? ? ?Element f1 = document.getElementById("ptab-0"); ? ? ? ? ? ? ? ?Element f2 = f1.child(0); ? ? ? ? ? ? ? ?//取地區(qū)class標簽父節(jié)點
? ? ? ? ? ? ? ?Element f3 = f2.child(0); ? ? ? ? ? ? ? ?//取數(shù)字父節(jié)點
? ? ? ? ? ? ? ?Element f4 = f2.child(2).child(0); ? ? ? ? ? ? ? ?//獲取標簽屬性值
? ? ? ? ? ? ? ?String areaClassName = f3.child(0).attr("class"); ? ? ? ? ? ? ? ?String numClassName = f4.child(1).attr("class"); ? ? ? ? ? ? ? ?RealTimeData realTimeData = new RealTimeData(); ? ? ? ? ? ? ? ?//地區(qū)
? ? ? ? ? ? ? ?Element e1 = document.getElementsByClass(areaClassName).get(0);
? ? ? ? ? ? ? ?realTimeData.setPlace(e1.text()); ? ? ? ? ? ? ? ?//現(xiàn)存確診
? ? ? ? ? ? ? ?Element e2 = document.getElementsByClass(numClassName).get(0);
? ? ? ? ? ? ? ?realTimeData.setExitDiagnosis(CommonUtil.strToNum(e2.text())); ? ? ? ? ? ? ? ?//累計確診
? ? ? ? ? ? ? ?Element e3 = document.getElementsByClass(numClassName).get(4);
? ? ? ? ? ? ? ?realTimeData.setCountDiagnosis(CommonUtil.strToNum(e3.text())); ? ? ? ? ? ? ? ?//境外輸入
? ? ? ? ? ? ? ?Element e4 = document.getElementsByClass(numClassName).get(5);
? ? ? ? ? ? ? ?realTimeData.setAbroad(CommonUtil.strToNum(e4.text())); ? ? ? ? ? ? ? ?//無癥狀
? ? ? ? ? ? ? ?Element e5 = document.getElementsByClass(numClassName).get(1);
? ? ? ? ? ? ? ?realTimeData.setAsymptomatic(CommonUtil.strToNum(e5.text())); ? ? ? ? ? ? ? ?//現(xiàn)存疑似
? ? ? ? ? ? ? ?Element e6 = document.getElementsByClass(numClassName).get(2);
? ? ? ? ? ? ? ?realTimeData.setExitSuspected(CommonUtil.strToNum(e6.text())); ? ? ? ? ? ? ? ?//現(xiàn)存重癥
? ? ? ? ? ? ? ?Element e7 = document.getElementsByClass(numClassName).get(3);
? ? ? ? ? ? ? ?realTimeData.setExitSevere(CommonUtil.strToNum(e7.text())); ? ? ? ? ? ? ? ?//累計治愈
? ? ? ? ? ? ? ?Element e8 = document.getElementsByClass(numClassName).get(6);
? ? ? ? ? ? ? ?realTimeData.setCountCure(CommonUtil.strToNum(e8.text())); ? ? ? ? ? ? ? ?//累計死亡
? ? ? ? ? ? ? ?Element e9 = document.getElementsByClass(numClassName).get(7);
? ? ? ? ? ? ? ?realTimeData.setCountDeath(CommonUtil.strToNum(e9.text())); ? ? ? ? ? ? ? ?//當天日期
? ? ? ? ? ? ? ?realTimeData.setDate(CommonUtil.todayDate());
? ? ? ? ? ? ? ?log.info("頁面數(shù)據(jù)分析完畢,存入數(shù)據(jù)庫");
? ? ? ? ? ? ? ?realTimeDataService.addRealTimeData(realTimeData);
? ? ? ? ? ? ? ?log.info("國內(nèi)實時數(shù)據(jù)已保存"); ? ? ? ? ? ? ? ?break;
? ? ? ? ? ?}catch (Exception e){
? ? ? ? ? ? ? ?log.error("第 "+ (i+1) +" 次國內(nèi)分析實時疫情數(shù)據(jù)異常:"+e);
? ? ? ? ? ? ? ?i++;
? ? ? ? ? ?}
? ? ? ?}
? ?}
}
quarzt定時任務核心 代碼:
package com.gad.epidemicmanage.task;import com.gad.epidemicmanage.service.IJobAndTriggerService;import lombok.RequiredArgsConstructor;import lombok.extern.slf4j.Slf4j;import org.quartz.JobDataMap;import org.springframework.boot.ApplicationArguments;import org.springframework.boot.ApplicationRunner;import org.springframework.context.ConfigurableApplicationContext;import org.springframework.stereotype.Component;/**
* @Description: 定義啟動時配置定時任務
*/public class TaskStart implements ApplicationRunner { ? ?private final ConfigurableApplicationContext context; ? ?private final IJobAndTriggerService jobAndTriggerService; ? ?
? ?public void run(ApplicationArguments args) throws Exception { ? ? ? ?if (context.isActive()) { ? ? ? ? ? ?/**
? ? ? ? ? ? * 獲取實時疫情數(shù)據(jù),每天更新兩次
? ? ? ? ? ? */
? ? ? ? ? ?JobDataMap map = new JobDataMap();
? ? ? ? ? ?jobAndTriggerService.addJob("RealTimeDataTask", ? ? ? ? ? ? ? ? ? ?"com.gad.epidemicmanage.task.RealTimeDataTask", ? ? ? ? ? ? ? ? ? ?"default", "10 00 09,18 * * ? ",map);
? ? ? ?}
? ?}
}
根據(jù)隔離天數(shù)到期自動將高危用戶刪除
package com.gad.epidemicmanage.task;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;import com.gad.epidemicmanage.pojo.entity.States;import com.gad.epidemicmanage.service.IStatesService;import com.gad.epidemicmanage.service.IJobAndTriggerService;import lombok.extern.slf4j.Slf4j;import org.quartz.DisallowConcurrentExecution;import org.quartz.Job;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;import org.springframework.stereotype.Component;import javax.annotation.Resource;public class HomeQuarantineDayTask implements Job { ? ?
? ?IStatesService statesService; ? ?
? ?IJobAndTriggerService jobAndTriggerService; ? ?
? ?public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { ? ? ? ?Integer userId = jobExecutionContext.getJobDetail().getJobDataMap().getInt("userId"); ? ? ? ?States states = statesService.getOne(new LambdaQueryWrapper<States>()
? ? ? ? ? ? ? ?.eq(States::getUserId,userId)); ? ? ? ?//獲取當前剩余隔離天數(shù)
? ? ? ?int curDays = states.getHomeQuarantineDay(); ? ? ? ?//0天時刪除定時任務
? ? ? ?if (curDays == 0){
? ? ? ? ? ?jobAndTriggerService.deleteJob("com.gad.epidemicmanage.task.HomeQuarantineDayTask", ? ? ? ? ? ? ? ? ? ?"default");
? ? ? ? ? ?log.info("userId:" +userId + " 居家隔離已結(jié)束");
? ? ? ?}else{ ? ? ? ? ? ?//減一天后重新存入
? ? ? ? ? ?statesService.updateHomeQuarantineDay(userId,curDays-1);
? ? ? ?}
? ?}
}
權(quán)限控制核心配置類
package com.gad.epidemicmanage.config;import com.gad.epidemicmanage.service.impl.UserDetailServiceImpl;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.authentication.AuthenticationProvider;import org.springframework.security.authentication.dao.DaoAuthenticationProvider;import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import javax.annotation.Resource;/**
* @author ?znz
* @date ?2022/2/18 14:42
* @desc security配置類
**/public class SecurityConfig extends WebSecurityConfigurerAdapter { ? ?
? ?
? ?public UserDetailServiceImpl userDetailsService() { return new UserDetailServiceImpl(); } ? ?
? ?protected void configure(HttpSecurity http) throws Exception {
? ? ? ?http ? ? ? ? ? ? ? ?//不受認證: /login
? ? ? ? ? ? ? ?.authorizeRequests()
? ? ? ? ? ? ? ?.antMatchers("/user/login").permitAll();
? ? ? ?http.httpBasic().disable() ? ? ? ? ? ? ? ?//關(guān)閉formLogin 自定義controller
? ? ? ? ? ? ? ?.formLogin().disable()
? ? ? ? ? ? ? ?.csrf().disable()
? ? ? ? ? ? ? ?.logout().disable();
? ?} ? ?
? ?
? ?//注入authenticationManager
? ?public AuthenticationManager authenticationManager() throws Exception { ? ? ? ?return super.authenticationManager();
? ?} ? ?
? ?public AuthenticationProvider daoAuthenticationProvider() { ? ? ? ?DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
? ? ? ?daoAuthenticationProvider.setUserDetailsService(userDetailsService());
? ? ? ?daoAuthenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
? ? ? ?daoAuthenticationProvider.setHideUserNotFoundExceptions(false); ? ? ? ?return daoAuthenticationProvider;
? ?} ? ?
? ?public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
? ? ? ?authenticationManagerBuilder
? ? ? ? ? ? ? ?.authenticationProvider(daoAuthenticationProvider());
? ?}
}
跨域訪問配置
package com.gad.epidemicmanage.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.stereotype.Component;import org.springframework.web.cors.CorsConfiguration;import org.springframework.web.cors.UrlBasedCorsConfigurationSource;import org.springframework.web.filter.CorsFilter;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/**
* @author ?znz
* @date ?2022/2/15 17:27
* @desc ?全局跨域配置類
**/public class GlobalCorsConfig implements Filter { ? ?
? ?public 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-Methods", "*");
? ? ? ?response.setHeader("Access-Control-Max-Age", "3600");
? ? ? ?response.setHeader("Access-Control-Allow-Headers", "*");
? ? ? ?response.setHeader("Access-Control-Allow-Credentials", "true");
? ? ? ?chain.doFilter(req, res);
? ?}
}
用戶管理控制器
package com.gad.epidemicmanage.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;import com.baomidou.mybatisplus.core.metadata.IPage;import com.gad.epidemicmanage.common.GlobalConstant;import com.gad.epidemicmanage.pojo.dto.UpdatePasswdDto;import com.gad.epidemicmanage.pojo.dto.UserListDto;import com.gad.epidemicmanage.pojo.dto.UserRigisterDto;import com.gad.epidemicmanage.pojo.entity.User;import com.gad.epidemicmanage.pojo.vo.Result;import com.gad.epidemicmanage.service.IRoleService;import com.gad.epidemicmanage.service.IUserBaseInfoService;import com.gad.epidemicmanage.service.IUserService;import lombok.extern.slf4j.Slf4j;import org.springframework.transaction.annotation.Transactional;import org.springframework.transaction.interceptor.TransactionAspectSupport;import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;/**
* @author ?znz
* @date ?2022/2/4 13:56
* @desc 用戶管理controller
**/public class UserController { ? ?
? ?IUserService userService; ? ?
? ?IUserBaseInfoService userBaseInfoService; ? ?
? ?IRoleService roleService; ? ?/**
? ? * 賬戶注冊
? ? */
? ?
? ?public Result accountRegister({
? ? ? ?log.info( UserRigisterDto userRigisterDto)"開始注冊"); ? ? ? ?Result result = new Result(true, "注冊成功"); ? ? ? ?try{ ? ? ? ? ? ?int flag = userService.insertUser(userRigisterDto); ? ? ? ? ? ?//根據(jù)返回值判斷是否重名,重名未注冊成功
? ? ? ? ? ?if(flag == GlobalConstant.STATE_FALSE){
? ? ? ? ? ? ? ?result.setMessage("注冊失敗,用戶名已被使用");
? ? ? ? ? ?} else if(flag == 2){
? ? ? ? ? ? ? ?result.setMessage("注冊失敗,兩次輸入密碼不一致");
? ? ? ? ? ?}else{
? ? ? ? ? ? ? ?result.setData(userService.getOne(new LambdaQueryWrapper<User>()
? ? ? ? ? ? ? ?.eq(User::getUserName,userRigisterDto.getUserName())));
? ? ? ? ? ? ? ?log.info("注冊成功");
? ? ? ? ? ?}
? ? ? ?}catch (Exception e){
? ? ? ? ? ?log.error("注冊失?。?#34;+e);
? ? ? ? ? ?result.setCode(GlobalConstant.REQUEST_ERROR_STATUS_CODE);
? ? ? ? ? ?result.setMessage("注冊失敗");
? ? ? ?} ? ? ? ?return result;
? ?} ? ?/**
? ? * 條件分頁查詢所有用戶
? ? */
? ?
? ?public Result queryUsers({
? ? ? ?log.info( UserListDto userListDto)"查詢所有用戶開始"); ? ? ? ?Result result = new Result(true, "查詢所有用戶成功"); ? ? ? ?try{
? ? ? ? ? ?IPage<User> userPage = userService.queryUsers(userListDto);
? ? ? ? ? ?result.setData(userPage);
? ? ? ? ? ?log.info("查詢所有用戶成功");
? ? ? ?}catch (Exception e){
? ? ? ? ? ?log.error("查詢所有用戶失?。?#34;+e);
? ? ? ? ? ?result.setCode(GlobalConstant.REQUEST_ERROR_STATUS_CODE);
? ? ? ? ? ?result.setMessage("查詢所有用戶失敗");
? ? ? ?} ? ? ? ?return result;
? ?} ? ?/**
? ? * 修改用戶密碼
? ? */
? ?
? ?public Result updateUser({
? ? ? ?log.info( UpdatePasswdDto updatePasswdDto)"修改用戶密碼開始"); ? ? ? ?Result result = new Result(true, "修改用戶密碼成功"); ? ? ? ?try{ ? ? ? ? ? ?Integer flag = userService.updateUser(updatePasswdDto); ? ? ? ? ? ?if(flag == GlobalConstant.STATE_FALSE){
? ? ? ? ? ? ? ?result.setMessage("原密碼錯誤,請檢查輸入"); ? ? ? ? ? ? ? ?return result;
? ? ? ? ? ?} ? ? ? ? ? ?if(flag == 2){
? ? ? ? ? ? ? ?result.setMessage("兩次密碼不一致,請檢查輸入"); ? ? ? ? ? ? ? ?return result;
? ? ? ? ? ?}
? ? ? ? ? ?log.info("修改用戶密碼成功");
? ? ? ?}catch (Exception e){
? ? ? ? ? ?log.error("修改用戶密碼失?。?#34;+e);
? ? ? ? ? ?result.setCode(GlobalConstant.REQUEST_ERROR_STATUS_CODE);
? ? ? ? ? ?result.setMessage("修改用戶密碼失敗");
? ? ? ?} ? ? ? ?return result;
? ?} ? ?/**
? ? * 刪除用戶,該操作會同時刪除用戶的詳細信息和角色還有狀態(tài)信息
? ? */
? ?
? ?
? ?public Result deleteUser({
? ? ? ?log.info( Integer userId)"開始刪除用戶"); ? ? ? ?Result result = new Result(true, "刪除用戶成功"); ? ? ? ?//設置回滾點
? ? ? ?Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint(); ? ? ? ?try{
? ? ? ? ? ?userService.deleteUser(userId);
? ? ? ? ? ?log.info("刪除用戶成功");
? ? ? ?}catch (Exception e){ ? ? ? ? ? ?//回滾事務
? ? ? ? ? ?TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
? ? ? ? ? ?log.error("刪除用戶失?。?#34;+e);
? ? ? ? ? ?result.setCode(GlobalConstant.REQUEST_ERROR_STATUS_CODE);
? ? ? ? ? ?result.setMessage("刪除用戶失敗");
? ? ? ?} ? ? ? ?return result;
? ?}
}
五,項目總結(jié)
經(jīng)過幾個月的努力與堅持,社區(qū)疫情防控管理系統(tǒng)終于完成了,關(guān)于社區(qū)防控的相關(guān)功能實現(xiàn)均按照初期的需求分析來進行并實現(xiàn),整個開發(fā)過程從明確用戶需求,到開發(fā)工具選擇,比如選擇什么框架,前后端是否要分離,再到具體的系統(tǒng)總體設計,做出總體設計說明書,再將總體設計細化為概要設計,以及后期的編碼實現(xiàn)和內(nèi)外部測試,最通過了系統(tǒng)的功能性測試。