# 高校健康上报系统设计与实现-Java后端 **Repository Path**: hsmus/health-system ## Basic Information - **Project Name**: 高校健康上报系统设计与实现-Java后端 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2022-03-02 - **Last Updated**: 2022-03-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 高校健康上报系统设计与实现 班级:18软卓1班 小组成员:黎梓鹏(201841404117)徐子煌(201741310421) ## 0. 大作业讲解视频在根目录下 ## 1. 项目介绍 ​ 在全国人民共同抗击新冠肺炎疫情的严峻形势下,为使高校师生健康信息及时汇报,便于了解健康状况,做好高校师生内部疫情防控和管理工作,特别设计开发高校健康上报系统。 ## 2. 需求分析 ### 2.1 前端界面功能模块 1. 界面美观、简洁、主题统一; 2. 调研国内相关系统界面的输入信息,设计前端各信息录入项目; 3. 有防止用户重复提交的功能; 4. 有加速渲染前端界面的设计。 ### 2.2 后端管理端功能 1. 使用`Vue + ElementUI`实现管理后台各个功能界面; 2. 界面简洁,主题统一; 3. 管理员账号管理模块; 4. 使用Spring Security安全框架实现认证、访问控制; 5. 账号管理模块,可以锁定账号; 6. 有解决系统高并发问题的设计; 7. 提供大数据报表并导出Excel表格,相关人员通过报表可以一目了然查看相关信息; 8. 所有列表可以进行综合查询,特别是时间字段,并可以排序; 9. 所有列表可以导出excel文件或者pdf文件; 10. 接入莞工中央认证 11. 后台登录使用自定义图形验证码 ## 3. 数据库设计 ### 3.1 中央认证表 > 注:该表保存通过中央认证登录的用户信息【用于填写健康上报表单前的登录认证】 ![1624866609218](resource/1624866609218.png) ### 3.2 管理员表 ![1624866665829](resource/1624866665829.png) ### 3.3 健康上报表 ![1624866695543](resource/1624866695543.png) ## 4. 前端设计 使用技术栈:Vue + ElementUI + axios + VueX + Echart ### 4.1 健康上报表单设计 > 健康上报表单代码仓库:https://gitee.com/alizipeng/health-system-front ![1625407108900](resource/1625407108900.png) ![1624886094638](resource/1624886094638.png) ### 4.2 中台管理系统设计 > 中台管理系统代码仓库:https://gitee.com/alizipeng/health-system-middle ![1624886146285](resource/1624886146285.png) ![1624886179060](resource/1624886179060.png) ![1624886201225](resource/1624886201225.png) ![1624886216229](resource/1624886216229.png) ![1624886236702](resource/1624886236702.png) ## 5. 后端设计 ### 5.1 技术方案 (1)开发框架:Spring Boot、Mybatis-plus (2)项目构建工具:Maven (3)权限控制:Spring Security。用于对登录的用户认证授权,进行访问控制。 (4)数据缓存/NoSQL:Redis。用于缓存常用数据,如省份数据等;以及做一些NoSQL查询;使用Redis防止消息重复消费 (5)消息队列:RabbitMQ。用于异步导出查询数据,将数据导出与主业务进行**解耦**。可将数据导出模块单独部署,当数据量很大时,可以防止导出模块与主业务模块抢夺服务器资源。同时使用了**延时队列**来删除过期的导出文件。 (6)数据导出:利用MyBatis的动态SQL功能,首先传入参数生成完整SQL,再把SQL发送到队列中,等待消费者进行消费。 ### 5.2 多模块项目结构 ![1624887173362](resource/1624887173362.png) ### 5.3 权限模块设计 ![1624887343071](resource/1624887343071.png) #### 5.3.1 中央认证安全配置 ```java package com.health.central_authentication.config; import com.health.central_authentication.filter.DGUTCheckTokenFilter; import com.health.central_authentication.handler.DGUTAccessDeniedHandler; import com.health.central_authentication.handler.DGUTAuthenticationEntryPoint; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import javax.annotation.Resource; /** * 莞工中央认证安全配置 * @author: zipeng Li * 2021/6/14 19:53 */ @Configuration @Order(99) public class DGUTSecurityConfig extends WebSecurityConfigurerAdapter { @Resource private DGUTAccessDeniedHandler dgutAccessDeniedHandler; @Resource private DGUTAuthenticationEntryPoint dgutAuthenticationEntryPoint; @Resource private DGUTCheckTokenFilter dgutCheckTokenFilter; /** * 配置权限资源 * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { http // 只拦截检查'/api/user/**'的请求 .antMatcher("/api/user/**").authorizeRequests().anyRequest().hasAuthority("USER") .and().csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .exceptionHandling() .authenticationEntryPoint(dgutAuthenticationEntryPoint) .accessDeniedHandler(dgutAccessDeniedHandler); http.addFilterBefore(dgutCheckTokenFilter, UsernamePasswordAuthenticationFilter.class); } } ``` #### 5.3.2 后台登录安全配置 ```java package com.health.admin.config; import com.health.admin.filter.CheckTokenFilter; import com.health.admin.handler.*; import com.health.security.impl.AdminDetailsService; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; 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.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import javax.annotation.Resource; /** * 后台管理系统安全配置 * @author: zipeng Li * 2021/6/13 12:58 */ @Configuration @Order(100) public class AdminSecurityConfig extends WebSecurityConfigurerAdapter { @Resource private AdminDetailsService adminDetailsService; @Resource private LoginSuccessHandler loginSuccessHandler; @Resource private LoginFailureHandler loginFailureHandler; @Resource private AdminAuthenticationEntryPoint adminAuthenticationEntryPoint; @Resource private AdminAccessDeniedHandler adminAccessDeniedHandler; @Resource private AdminLogoutSuccessHandler adminLogoutSuccessHandler; @Resource private CheckTokenFilter checkTokenFilter; @Value("${system.admin.login-url}") private String loginUrl; @Value("${system.admin.logout-url}") private String logoutUrl; @Bean public PasswordEncoder passwordEncoder() { // 明文+随机盐值》加密存储 return new BCryptPasswordEncoder(); } /** * 配置权限资源 * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { http // 只拦截检查'/api/admin/**'的请求 .antMatcher("/api/admin/**").authorizeRequests() .antMatchers(loginUrl, "/api/admin/image","/api/admin/testMq").permitAll() .anyRequest().hasAuthority("ADMIN") .and().formLogin() .loginProcessingUrl(loginUrl) // 自定义的登录验证成功或失败后的去向 .successHandler(loginSuccessHandler) .failureHandler(loginFailureHandler) .and().logout() .logoutUrl(logoutUrl) .logoutSuccessHandler(adminLogoutSuccessHandler) // 禁用csrf防御机制(跨域请求伪造),这么做在测试和开发会比较方便。 .and().csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .exceptionHandling() .authenticationEntryPoint(adminAuthenticationEntryPoint) .accessDeniedHandler(adminAccessDeniedHandler); http.addFilterBefore(checkTokenFilter, UsernamePasswordAuthenticationFilter.class); } /** * 配置认证处理器 * 自定义的UserDetailsService * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(adminDetailsService); } } ``` ### 5.4 数据导出模块设计 #### 5.4.1 消息队列部分设计 分为两个消费者: `DataStatsTaskReceiver`的功能为 1. 执行SQL并导出Excel文件,然后把文件上传到七牛云中,再将任务状态更新为成功,客户端便可下载文件; 2. 成功导出文件后,会给文件设置一个有效期,过期之后将从七牛云删除。具体实现为发送延时消息到延迟队列中。 `DelayTaskReceiver`为延迟队列的消费者,功能为接收`DataStatsTaskReceiver`发送过来的文件ID,等到有效期到达之后,会对文件进行删除。具体实现为使用了RabbitMQ延时队列插件。 `DataStatsTaskReceiver`实现: ```java @RabbitListener(queues = DataStatsTaskQueueConstants.STATS_TASK_QUEUE_NAME) public void handler(Message message, Channel channel) throws IOException { DataStatsTask dataStatsTask = (DataStatsTask) message.getPayload(); MessageHeaders headers = message.getHeaders(); Long tag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG); String msgId = (String) headers.get("spring_returned_message_correlation"); logger.info("Received Task:{}",dataStatsTask.toString()); // 设置唯一消息id,防止重复消费 if (redisTemplate.opsForHash().entries("stats_task_log").containsKey(msgId)) { //redis 中包含该 key,说明该消息已经被消费过 logger.info(msgId + ":消息已经被消费"); channel.basicAck(tag, false);//确认消息已消费 return; } String sql = dataStatsTask.getSql(); String key = dataStatsTask.getTaskId(); // 在redis中设置该任务的状态 redisTemplate.opsForHash().put("export_task",dataStatsTask.getTaskId(),"processing"); if(dbUtil.extractToExcel(sql,path,key)){ String local = path+key; String url = QiNiuUtil.upload(local,key); if(url==null){ redisTemplate.opsForHash().delete("export_task",dataStatsTask.getTaskId()); return; } redisTemplate.opsForHash().put("export_task",dataStatsTask.getTaskId(),url); // 发送延时任务 sendDelayTask(key,dataStatsTask.getExpired()); } } /** * 发送延时任务,msg为id,delayTime为文件有效期 */ public void sendDelayTask(String msg,Integer delayTime){ rabbitTemplate.convertAndSend(DelayDeleteQueueConstants.DELAY_DELETE_EXCHANGE_NAME, DelayDeleteQueueConstants.DELAY_DELETE_ROUTING_KEY_NAME, msg, a ->{ a.getMessageProperties().setDelay(delayTime); return a; }); } ``` `DelayTaskReceiver`配置: ```java @Configuration public class DelayedRabbitMQConfig { @Bean public Queue immediateQueue() { return new Queue(DelayDeleteQueueConstants.DELAY_DELETE_QUEUE_NAME); } @Bean public CustomExchange customExchange() { Map args = new HashMap<>(); args.put("x-delayed-type", "direct"); return new CustomExchange(DelayDeleteQueueConstants.DELAY_DELETE_EXCHANGE_NAME, "x-delayed-message", true, false, args); } @Bean public Binding bindingNotify(@Qualifier("immediateQueue") Queue queue, @Qualifier("customExchange") CustomExchange customExchange) { return BindingBuilder.bind(queue).to(customExchange) .with(DelayDeleteQueueConstants.DELAY_DELETE_ROUTING_KEY_NAME).noargs(); } } ``` `DelayTaskReceiver`实现: ```java @RabbitListener(queues = DelayDeleteQueueConstants.DELAY_DELETE_QUEUE_NAME) public void handler(Message message, Channel channel) throws IOException { String taskId = String.valueOf(message.getPayload()); logger.debug("delete expired task:{}",taskId); QiNiuUtil.deleteFile(taskId); redisTemplate.opsForHash().delete("export_task",taskId); } ``` #### 5.4.2 数据导出工具类 执行SQL,然后导出为Excel,会自动添加表头 ```java public boolean extractToExcel(String sql,String path,String fileName){ try { ResultSet resultSet = execute(sql); ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); List> ret = new ArrayList<>(); List header = new ArrayList<>(); int colCount = resultSetMetaData.getColumnCount(); for(int i=1;i<=colCount;i++) header.add(resultSetMetaData.getColumnName(i)); // 添加表头 ret.add(header); while (resultSet.next()){ List row = new ArrayList<>(); for(int i=1;i<=colCount;i++) row.add(resultSet.getObject(i)); ret.add(row); } DataToExcel.ToExcel(ret,path,fileName); } catch (SQLException throwables) { throwables.printStackTrace(); return false; } return true; } ``` 以下为生成SQL代码: ```java /** * 运行期获取MyBatis执行的SQL及参数 * * @param id Mapper xml 文件里的select Id * @param obj 参数 * @param sqlSessionFactory * @return */ public static String getMyBatisSql(String id, Object obj, SqlSessionFactory sqlSessionFactory) { MappedStatement ms = sqlSessionFactory.getConfiguration().getMappedStatement(id); BoundSql boundSql = ms.getBoundSql(obj); String sql = boundSql.getSql(); List parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { Object[] parameterArray = new Object[parameterMappings.size()]; ParameterMapping parameterMapping = null; Object value = null; Object parameterObject = null; MetaObject metaObject = null; PropertyTokenizer prop = null; String propertyName = null; String[] names = null; for (int i = 0; i < parameterMappings.size(); i++) { parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() != ParameterMode.OUT) { propertyName = parameterMapping.getProperty(); names = propertyName.split("\\."); if (propertyName.indexOf(".") != -1 && names.length == 2) { parameterObject = boundSql.getAdditionalParameter(names[0]); propertyName = names[1]; } else if (propertyName.indexOf(".") != -1 && names.length == 3) { parameterObject = boundSql.getAdditionalParameter(names[0]); // map if (parameterObject instanceof Map) { parameterObject = ((Map) parameterObject).get(names[1]); } propertyName = names[2]; } else { parameterObject = boundSql.getAdditionalParameter(propertyName); } if (null == parameterObject) { parameterObject = getFieldValueByFieldName(propertyName, obj); } prop = new PropertyTokenizer(propertyName); if (parameterObject == null) { value = null; } else if (ms.getConfiguration().getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else if (boundSql.hasAdditionalParameter(propertyName)) { value = boundSql.getAdditionalParameter(propertyName); } else if (propertyName.startsWith(ForEachSqlNode.ITEM_PREFIX) && boundSql.hasAdditionalParameter(prop.getName())) { value = boundSql.getAdditionalParameter(prop.getName()); } else { value = metaObject == null ? null : metaObject.getValue(propertyName); } parameterArray[i] = value; } parameterObject = null; } int i = 0; while (sql.indexOf("?") != -1) { if (null == parameterArray[i]) { throw new RuntimeException("mybatis获取sql异常"); } if (parameterArray[i] instanceof String) { sql = sql.replaceFirst("\\?", "'" + parameterArray[i].toString() + "'"); } else { sql = sql.replaceFirst("\\?", parameterArray[i].toString()); } i++; } int index; StringBuilder sb = new StringBuilder(); for (String s : sql.split("\n")) { index = s.indexOf("--"); if (-1 == index) { index = s.length(); } sb.append(s.substring(0, index).replace("\t", " ").trim()).append(" "); } return sb.toString().replaceAll("(\r?\n(\\s*\r?\n)+)", " ").replaceAll("\n", " ").replaceAll("\r", " ").replaceAll(" ", " ").replaceAll(" ", " ").replaceAll(" ", " "); } return sql; } ``` Controller调用代码: ```java @GetMapping("/stats/temperature") public ResultVo getStatsTemperature(@RequestParam("temperature")float temperature, @RequestParam("time")String time) { SqlSessionFactory sqlSessionFactory = null; try { sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("stats-mybatis.xml")); } catch (IOException e) { e.printStackTrace(); return ResultUtils.error("Server error"); } TemperStatsParam sParam = new TemperStatsParam(); sParam.setTemperature(temperature); sParam.setTime(time); String sql = MybatisSQLUtil.getMyBatisSql("StatsMapper.getTemperStats", sParam, sqlSessionFactory); DataStatsTask dataStatsTask = new DataStatsTask(UUID.randomUUID().toString()+".xls", sql,60000); sendDataStatsTask(dataStatsTask); return ResultUtils.success(dataStatsTask.getTaskId()); } ``` Mapper: ![Image description](https://images.gitee.com/uploads/images/2021/0701/224918_4c6a1447_647370.png "屏幕截图.png") ### 5.5 公共模块设计 ![1625021243398](resource/1625021243398.png) ### 5.6 实体类 ![1625021332422](resource/1625021332422.png) ### 5.7 DAO层 ![1625021371507](resource/1625021371507.png) ### 5.8 Service层 ![1625021382094](resource/1625021382094.png) ### 5.9 接口层 ![1625021391785](resource/1625021391785.png) ### 5.10 中央认证设计 ```java package com.health.central_authentication; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.health.security.CentralAuthenticationToken; import com.health.security.Student; import com.health.security.StudentService; import com.health.util.JwtUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.json.JacksonJsonParser; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.WebAttributes; import org.springframework.util.LinkedMultiValueMap; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Map; /** * @author: zipeng Li * 2021/6/14 16:42 */ @Slf4j @RestController public class CentralAuthenticationController { private static final String appid = "javaee"; private static final String appSecret = "b3b52e43ccfd"; private static final RestTemplate rest = new RestTemplate(); private static final JacksonJsonParser jsonParser = new JacksonJsonParser(); private static final String GetAccessTokenURL = "https://cas.dgut.edu.cn/ssoapi/v2/checkToken"; private static final String GetInfoURL = "https://cas.dgut.edu.cn/oauth/getUserInfo"; @Resource private StudentService studentService; @GetMapping("/api/central/login") public void login(HttpServletRequest request, HttpServletResponse response) throws IOException { // 重定向到中央认证 response.sendRedirect("https://cas.dgut.edu.cn?appid=" + appid); } @GetMapping("/login/dgut") public void callBack(HttpServletRequest request, HttpServletResponse response) throws IOException { // 新建未认证的 authentication String token = request.getParameter("token"); CentralAuthenticationToken centralAuthenticationToken = new CentralAuthenticationToken(token); try { centralAuthenticationToken = authenticate(centralAuthenticationToken); } catch (AuthenticationException e) { // 如果校验失败providerManager会抛异常,在catch里作异常处理。 response.sendRedirect("https://cas.dgut.edu.cn?appid=" + appid); return; } // 校验成功,执行后面的流程: SecurityContextHolder.getContext().setAuthentication(centralAuthenticationToken); // 移除之前认证时的错误信息 request.getSession().removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION); // 生产token返回 JwtUtils jwtUtils = new JwtUtils(); String res = jwtUtils.generateTokenByCentralAuthenticationToken(centralAuthenticationToken); log.info(res); response.sendRedirect("http://localhost:8081?token=" + res); } private CentralAuthenticationToken authenticate(Authentication authentication) throws AuthenticationException { // 1.强转 未认证的CentralAuthenticationToken CentralAuthenticationToken authenticationToken = (CentralAuthenticationToken) authentication; // 2.向中央认证服务器发送请求获取 openid 和 access_token LinkedMultiValueMap map = new LinkedMultiValueMap<>(); map.add("token", authenticationToken.getToken()); map.add("appid", appid); map.add("appsecret", appSecret); Map stringObjectMap = jsonParser.parseMap(rest.postForObject(GetAccessTokenURL, map, String.class)); String accessToken = (String) stringObjectMap.get("access_token"); String openid = (String) stringObjectMap.get("openid"); // 3.向中央认证服务器发送请求获取个人信息 map.clear(); map.add("access_token", accessToken); map.add("openid", openid); Map objectMap = jsonParser.parseMap(rest.postForObject(GetInfoURL, map, String.class)); // 4.认证成功,重新生产 authentication Student student = new Student(); student.setUsername((String)objectMap.get("username")); student.setName((String)objectMap.get("name")); student.setWxOpenid((String)objectMap.get("wx_openid")); student.setFacultyTitle((String)objectMap.get("faculty_title")); student.setOpenid((String)objectMap.get("openid")); // 5. 判断数据库是否已经存在该用户 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(Student::getUsername, student.getUsername()); studentService.saveOrUpdate(student, wrapper); return new CentralAuthenticationToken(student, AuthorityUtils.createAuthorityList("USER")); } } ``` ### 5.11 其他核心接口设计 #### 5.11.1 后台管理相关 ```java /** * 管理员控制器 * @author: zipeng Li * 2021/6/13 15:50 */ @Slf4j @RestController @RequestMapping("/api/admin") public class AdminController { @Resource private DefaultKaptcha defaultKaptcha; @Resource private AdminService adminService; @Resource private StudentService studentService; @Resource private ReportFormService reportFormService; @Resource private PasswordEncoder passwordEncoder; @Autowired StringRedisTemplate redisTemplate; @Autowired RabbitTemplate rabbitTemplate; @GetMapping("/stats/temperature") public ResultVo getStatsTemperature(@RequestParam("temperature")float temperature, @RequestParam("time")String time) { SqlSessionFactory sqlSessionFactory = null; try { sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("stats-mybatis.xml")); } catch (IOException e) { e.printStackTrace(); return ResultUtils.error("Server error"); } TemperStatsParam sParam = new TemperStatsParam(); sParam.setTemperature(temperature); sParam.setTime(time); String sql = MybatisSQLUtil.getMyBatisSql("StatsMapper.getTemperStats", sParam, sqlSessionFactory); DataStatsTask dataStatsTask = new DataStatsTask(UUID.randomUUID().toString()+".xls", sql,60000); sendDataStatsTask(dataStatsTask); return ResultUtils.success(dataStatsTask.getTaskId()); } @GetMapping("/stats/region") public ResultVo getStatsTemperature(@RequestParam("country")String country, @RequestParam(value = "province",required = false)String province, @RequestParam(value = "district",required = false)String district) { SqlSessionFactory sqlSessionFactory = null; try { sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("stats-mybatis.xml")); } catch (IOException e) { e.printStackTrace(); return ResultUtils.error("Server error"); } RegionStatsParam sParam = new RegionStatsParam(); sParam.setCountry(country); sParam.setProvince(province); sParam.setDistrict(district); String sql = MybatisSQLUtil.getMyBatisSql("StatsMapper.getRegionStats", sParam, sqlSessionFactory); DataStatsTask dataStatsTask = new DataStatsTask(UUID.randomUUID().toString()+".xls", sql,60000); sendDataStatsTask(dataStatsTask); return ResultUtils.success(dataStatsTask.getTaskId()); } @GetMapping("/stats/task") public ResultVo getStatsFileId(@RequestParam("id")String id){ String url = String.valueOf(redisTemplate.opsForHash().get("export_task",id)); log.info(url); if(url.equals("null")) return ResultUtils.error("任务不存在"); else if(url.equals("process")) return ResultUtils.error("任务导出中"); else return ResultUtils.success("导出成功,请在10分钟内下载",url); } /** * 后台登录,获取图形验证码 * @param request * @param response * @throws IOException */ @RequestMapping("image") public void imageCode(HttpServletRequest request, HttpServletResponse response) throws IOException { //设置页面缓存方式 不缓存,不存储 response.setHeader("Cache-Control","no-store, no-cache"); //设置以图片的形式响应 response.setContentType("image/jpeg"); //1.获取验证码字符 String text = defaultKaptcha.createText(); log.info("获取验证码:" + text); //2.存储到session中 request.getSession().setAttribute("code",text); //3.生成验证码图片 BufferedImage image = defaultKaptcha.createImage(text); //4.输出给前端 ServletOutputStream out = response.getOutputStream(); ImageIO.write(image,"jpg",out); if(out != null){ out.close(); } } /** * 添加管理员 * @param admin * @return */ @PostMapping("add-admin") public ResultVo addAdmin(@RequestBody Admin admin){ // 检查权限 Admin principal =(Admin) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if(! "1".equals(principal.getIsAdmin())){ return ResultUtils.error("无此操作权限"); } //查询用户是否存在 Admin one = adminService.getAdminByUserName(admin.getUsername()); if(one != null){ return ResultUtils.error("用户名已经存在!"); } //加密用户密码 String pwd = passwordEncoder.encode(admin.getPassword()); admin.setPassword(pwd); boolean b = adminService.save(admin); if(b){ return ResultUtils.success("新增管理员成功"); }else{ return ResultUtils.error("新增管理员失败"); } } /** * 管理员锁定 * @param lockAdmin * @return */ @PostMapping("lock-admin") public ResultVo LockAdmin(@RequestBody LockAdmin lockAdmin){ // 检查权限 Admin principal =(Admin) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if(! "1".equals(principal.getIsAdmin())){ return ResultUtils.error("无此操作权限", CodeStatus.NO_AUTH); } // 检查是否存在该用户 Admin admin = adminService.getById(lockAdmin.getId()); if (admin == null) { return ResultUtils.error("不存在该用户", CodeStatus.ERROR_CODE); } // 锁定用户 admin.setAccountNonLocked(lockAdmin.isLock()); adminService.saveOrUpdate(admin); return ResultUtils.success(lockAdmin.isLock()?"解锁成功":"锁定成功"); } /** * 管理员列表 * @param parm * @return */ @PostMapping("list") public ResultVo getList(@RequestBody ParmVo parm){ IPage page = new Page<>(); page.setCurrent(parm.getStartIndex()); page.setSize(parm.getPageSize()); IPage adminIPage = adminService.page(page); return ResultUtils.success("查询成功", adminIPage); } /** * 用户列表 * @param parm * @return */ @PostMapping("student-list") public ResultVo getStudentList(@RequestBody ParmVo parm){ IPage page = new Page<>(); page.setCurrent(parm.getStartIndex()); page.setSize(parm.getPageSize()); IPage adminIPage = studentService.page(page); return ResultUtils.success("查询成功", adminIPage); } void sendDataStatsTask(DataStatsTask dataStatsTask) { rabbitTemplate.convertAndSend(DataStatsTaskQueueConstants.STATS_TASK_EXCHANGE_NAME, DataStatsTaskQueueConstants.STATS_TASK_ROUTING_KEY_NAME, dataStatsTask, a -> { a.getMessageProperties().setCorrelationId(dataStatsTask.getTaskId()); return a; }); } /** * 获取填报列表 * @param parmVo * @return */ @PostMapping("report-list") public ResultVo reportList(@RequestBody ParmVo parmVo){ IPage page = new Page<>(); page.setCurrent(parmVo.getStartIndex()); page.setSize(parmVo.getPageSize()); IPage adminIPage = reportFormService.page(page); return ResultUtils.success("查询成功", adminIPage); } /** * 获取表单详情 * @param id * @return */ @GetMapping("report-detail") public ResultVo reportDetail(@RequestParam Long id){ ReportForm reportForm = reportFormService.getById(id); Student student = studentService.getById(reportForm.getCentralAuthenticationId()); HashMap map = new HashMap<>(); map.put("reportForm", reportForm); map.put("student", student); return ResultUtils.success("查询成功", map); } /** * 获取统计数据 * @return */ @GetMapping("statistical-data") public ResultVo reportDetail(){ // 获取用户人数 Integer studentNumber = studentService.list().size(); // 获取管理员人数 Integer adminNumber = adminService.list().size(); // 获取今日填报人数 Integer dayRecord = reportFormService.getDayRecords(); // 获取风险人数 Integer dangerNumber = reportFormService.getDangerNumber(); HashMap map = new HashMap<>(4); map.put("studentNumber", studentNumber); map.put("adminNumber", adminNumber); map.put("dayRecord", dayRecord); map.put("dangerNumber", dangerNumber); return ResultUtils.success("获取统计信息", map); } } ``` #### 5.11.2 表单相关 ```java /** * @author: zipeng Li * 2021/6/16 11:48 */ @Slf4j @RestController @RequestMapping("/api/user") public class StudentController { @GetMapping("student-info") public ResultVo studentInfo(){ CentralAuthenticationToken authentication = (CentralAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); return ResultUtils.success("获取用户信息成功", authentication.getStudent()); } } /** * @author: zipeng Li * 2021/6/20 16:53 */ @Slf4j @RestController @RequestMapping("/api/user") public class reportController { @Resource private ReportFormService reportFormService; /** * 提交表单 * @param reportForm * @return */ @PostMapping("report-form") public ResultVo reportForm(@RequestBody ReportForm reportForm){ // 判断当前用户是否已经提交 CentralAuthenticationToken authentication = (CentralAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); Student student = authentication.getStudent(); ReportForm one = reportFormService.getDayRecord(student.getId()); if (one != null) return ResultUtils.error("当日已经打卡,勿重复提交"); // 保存数据库 reportForm.setCentralAuthenticationId(student.getId()); reportForm.setName(student.getName()); reportFormService.save(reportForm); return ResultUtils.success("打卡成功"); } /** * 判断今天是否提交成功 * @return */ @PostMapping("check-report") public ResultVo checkReport(){ // 判断当前用户是否已经提交 CentralAuthenticationToken authentication = (CentralAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); Student student = authentication.getStudent(); ReportForm one = reportFormService.getDayRecord(student.getId()); if (one != null) return ResultUtils.success("您今天已经提交成功啦", true); return ResultUtils.success("您今天还没提交哦", false); } } ``` 5.11.3