├── .gitignore ├── LICENSE ├── README.md ├── exam-admin ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── senior │ │ ├── ExamApplication.java │ │ ├── config │ │ ├── CorsConfig.java │ │ ├── DruidConfig.java │ │ ├── Interceptor │ │ │ ├── AdminInterceptor.java │ │ │ ├── StudentInterceptor.java │ │ │ ├── TeacherInterceptor.java │ │ │ └── WebAppConfigurer.java │ │ ├── MybatisPlusConfig.java │ │ └── RedisConfig.java │ │ ├── constant │ │ └── ExamConstant.java │ │ ├── controller │ │ ├── AdminController.java │ │ ├── CommonController.java │ │ ├── StudentController.java │ │ ├── TeacherController.java │ │ └── UtilController.java │ │ ├── entity │ │ ├── Answer.java │ │ ├── Exam.java │ │ ├── ExamQuestion.java │ │ ├── ExamRecord.java │ │ ├── Major.java │ │ ├── Notice.java │ │ ├── Question.java │ │ ├── QuestionBank.java │ │ ├── User.java │ │ └── UserRole.java │ │ ├── mapper │ │ ├── AnswerMapper.java │ │ ├── ExamMapper.java │ │ ├── ExamQuestionMapper.java │ │ ├── ExamRecordMapper.java │ │ ├── MajorMapper.java │ │ ├── NoticeMapper.java │ │ ├── QuestionBankMapper.java │ │ ├── QuestionMapper.java │ │ ├── UserMapper.java │ │ └── UserRoleMapper.java │ │ ├── service │ │ ├── AnswerService.java │ │ ├── ExamQuestionService.java │ │ ├── ExamRecordService.java │ │ ├── ExamService.java │ │ ├── MajorService.java │ │ ├── NoticeService.java │ │ ├── QuestionBankService.java │ │ ├── QuestionService.java │ │ ├── UserRoleService.java │ │ ├── UserService.java │ │ └── impl │ │ │ ├── AnswerServiceImpl.java │ │ │ ├── ExamQuestionServiceImpl.java │ │ │ ├── ExamRecordServiceImpl.java │ │ │ ├── ExamServiceImpl.java │ │ │ ├── MajorServiceImpl.java │ │ │ ├── NoticeServiceImpl.java │ │ │ ├── QuestionBankServiceImpl.java │ │ │ ├── QuestionServiceImpl.java │ │ │ ├── UserRoleServiceImpl.java │ │ │ └── UserServiceImpl.java │ │ ├── util │ │ ├── CheckToken.java │ │ ├── CreateVerificationCode.java │ │ ├── RedisUtil.java │ │ ├── SaltEncryption.java │ │ └── TokenUtils.java │ │ └── vo │ │ ├── AddExamByBankVo.java │ │ ├── AddExamByQuestionVo.java │ │ ├── BankHaveQuestionSum.java │ │ ├── CommonResult.java │ │ ├── ExamQueryVo.java │ │ ├── ExamState.java │ │ ├── QuestionVo.java │ │ └── TokenVo.java │ └── resources │ ├── application.yml │ └── mapper │ ├── MajorMapper.xml │ ├── NoticeMapper.xml │ ├── UserMapper.xml │ └── UserRoleMapper.xml ├── exam-vue ├── .browserslistrc ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── babel.config.js ├── debug.log ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.vue │ ├── api │ │ └── api.js │ ├── assets │ │ ├── css │ │ │ └── global.css │ │ ├── imgs │ │ │ ├── bg.png │ │ │ ├── examTitle.png │ │ │ ├── favicon.png │ │ │ ├── judge.png │ │ │ ├── multiple.png │ │ │ ├── order.png │ │ │ ├── random.png │ │ │ ├── single.png │ │ │ ├── true.png │ │ │ ├── wellcome.5bb22a17.jpg │ │ │ ├── wellcome.jpg │ │ │ └── wellcome.png │ │ └── logo.png │ ├── components │ │ ├── AddExam.vue │ │ ├── Dashboard.vue │ │ ├── ExamManage.vue │ │ ├── ExamOnline.vue │ │ ├── ExamPage.vue │ │ ├── ExamResult.vue │ │ ├── Login.vue │ │ ├── Main.vue │ │ ├── Major.vue │ │ ├── MarkExamPage.vue │ │ ├── MarkManage.vue │ │ ├── MyGrade.vue │ │ ├── MyQuestionBank.vue │ │ ├── NoticeManage.vue │ │ ├── QuestionBankManage.vue │ │ ├── QuestionManage.vue │ │ ├── QuestionTk.vue │ │ ├── Register.vue │ │ ├── RoleManage.vue │ │ ├── StatisticOverview.vue │ │ ├── TrainPage.vue │ │ ├── UpdateExam.vue │ │ └── UserManage.vue │ ├── main.js │ ├── plugins │ │ └── element.js │ └── router │ │ └── index.js └── vue.config.js ├── sql └── exam.sql ├── 初始用户1.png ├── 初始用户2.png ├── 在线考试系统设计文档.pdf ├── 说明.txt └── 项目开发环境手册.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | target 5 | *.iml 6 | OSSUtil.java 7 | 8 | # local env files 9 | .env.local 10 | .env.*.local 11 | 12 | # Log files 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | pnpm-debug.log* 17 | 18 | # Editor directories and files 19 | .idea 20 | .vscode 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ExamOnline 2 | ## 基于SpringBoot、Vue、Redis的在线考试系统 3 | ### 主要性能 4 | 1、本项目采用了 Springboot + vue2.0 前后端分离模式设计,后端提供获取和显 示数据库数据的接口,前端采用 Vue 框架 Element-UI 前端组件库布局,使用 http 和 axios 向后端发送数据请求获得数据集,然后在前端的组件内部进行展示,前 后端分离的项目模式程序代码层次分明,便于维护和修改。同时还用到了 Echarts 图表工具对考试结果进行展示。 5 | 6 | 2、因为本项目已经部署到服务器上,为了提升服务器性能,使用了 Redis 保存 已经访问过的信息,使请求的数据信息得以持久化,提升高并发性能和访问速度。 7 | 8 | 3、在用户登录验证方面,采用了自生成 token 令牌,每次用户发送请求时都需 要检验该用户的 token 是否与当前登录用户匹配且是否超时等,提升系统安全性能。 9 | 10 | 4、在用户信息安全方面,采取非明文数据存储数据库的方式,使用的是 MD5 信息摘要算法将密码转成完全不同的 128 位信息摘要。这样即使数据库信息泄露,用户的密码也是安全的。 11 | 12 | 5、接口设计采用 restful 风格,接口文档基于 swagger; 6、基于 slf4j 和 Log4j2 实现系统运行日志采集,基于切面实现系统操作日志采集 13 | 14 | 15 | ### 功能模块 16 | ![](https://cdn.jsdelivr.net/gh/moon-Light404/my_picgo@master/img/20220808180456.png) 17 | 18 | ### 后端项目模块 19 | ![](https://cdn.jsdelivr.net/gh/moon-Light404/my_picgo@master/img/20220808180537.png) 20 | 21 | ### 前端项目模块 22 | ![image](https://user-images.githubusercontent.com/78211709/183393860-5287869c-51d9-44b9-9afe-b0a326764b0e.png) 23 | 24 | ### 整体调用关系 25 | ![](https://cdn.jsdelivr.net/gh/moon-Light404/my_picgo@master/img/20220808180632.png) 26 | 27 | ### 部分界面设计 28 | ![](https://cdn.jsdelivr.net/gh/moon-Light404/my_picgo@master/img/20220808181348.png) 29 | ![](https://cdn.jsdelivr.net/gh/moon-Light404/my_picgo@master/img/20220808181420.png) 30 | ![](https://cdn.jsdelivr.net/gh/moon-Light404/my_picgo@master/img/20220808181453.png) 31 | ![](https://cdn.jsdelivr.net/gh/moon-Light404/my_picgo@master/img/20220808181511.png) 32 | ![](https://cdn.jsdelivr.net/gh/moon-Light404/my_picgo@master/img/20220808181533.png) 33 | ![](https://cdn.jsdelivr.net/gh/moon-Light404/my_picgo@master/img/20220808181550.png) 34 | ![](https://cdn.jsdelivr.net/gh/moon-Light404/my_picgo@master/img/20220808181605.png) 35 | ![](https://cdn.jsdelivr.net/gh/moon-Light404/my_picgo@master/img/20220808181632.png) 36 | ![](https://cdn.jsdelivr.net/gh/moon-Light404/my_picgo@master/img/20220808181657.png) 37 | 在线考试页面: 38 | ![](https://cdn.jsdelivr.net/gh/moon-Light404/my_picgo@master/img/20220808181722.png) 39 | ![](https://cdn.jsdelivr.net/gh/moon-Light404/my_picgo@master/img/20220808181738.png) 40 | 成绩可视化 41 | ![](https://cdn.jsdelivr.net/gh/moon-Light404/my_picgo@master/img/20220808181802.png) 42 | -------------------------------------------------------------------------------- /exam-admin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.7.RELEASE 9 | 10 | 11 | com.senior 12 | exam-admin 13 | 0.0.1-SNAPSHOT 14 | exam-admin 15 | 在线考试系统 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | 28 | mysql 29 | mysql-connector-java 30 | runtime 31 | 32 | 33 | 34 | 35 | log4j 36 | log4j 37 | 1.2.17 38 | 39 | 40 | 41 | org.projectlombok 42 | lombok 43 | true 44 | 45 | 46 | 47 | 48 | com.auth0 49 | java-jwt 50 | 3.8.2 51 | 52 | 53 | 54 | 55 | io.springfox 56 | springfox-swagger2 57 | 2.9.2 58 | 59 | 60 | io.springfox 61 | springfox-swagger-ui 62 | 2.9.2 63 | 64 | 65 | 66 | com.alibaba 67 | druid 68 | 1.1.22 69 | 70 | 71 | 72 | org.springframework.boot 73 | spring-boot-starter-data-redis 74 | 75 | 76 | 77 | com.baomidou 78 | mybatis-plus-boot-starter 79 | 3.0.5 80 | 81 | 82 | 83 | org.springframework.boot 84 | spring-boot-starter-test 85 | test 86 | 87 | 88 | org.junit.vintage 89 | junit-vintage-engine 90 | 91 | 92 | 93 | 94 | org.apache.commons 95 | commons-lang3 96 | 3.12.0 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | org.springframework.boot 105 | spring-boot-maven-plugin 106 | 107 | com.senior.ExamApplication 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/ExamApplication.java: -------------------------------------------------------------------------------- 1 | package com.senior; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 7 | import org.springframework.stereotype.Controller; 8 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 9 | 10 | @SpringBootApplication 11 | @EnableSwagger2 12 | @Controller 13 | public class ExamApplication extends SpringBootServletInitializer { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(ExamApplication.class, args); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/config/CorsConfig.java: -------------------------------------------------------------------------------- 1 | package com.senior.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.cors.CorsConfiguration; 6 | import org.springframework.web.cors.UrlBasedCorsConfigurationSource; 7 | import org.springframework.web.filter.CorsFilter; 8 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 9 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 10 | 11 | @Configuration 12 | public class CorsConfig implements WebMvcConfigurer { 13 | @Override 14 | public void addCorsMappings(CorsRegistry registry) { 15 | registry.addMapping("/**") 16 | .allowedOrigins("*") 17 | .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS") 18 | .allowCredentials(true) 19 | .maxAge(3600) 20 | .allowedHeaders("*"); 21 | } 22 | 23 | // 让cors高于拦截器的权限 24 | @Bean 25 | public CorsFilter corsFilter() { 26 | CorsConfiguration config = new CorsConfiguration(); 27 | config.addAllowedOrigin("*"); 28 | config.setAllowCredentials(true); 29 | config.addAllowedMethod("*"); 30 | config.addAllowedHeader("*"); 31 | UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource(); 32 | configSource.registerCorsConfiguration("/**", config); 33 | return new CorsFilter(configSource); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/config/DruidConfig.java: -------------------------------------------------------------------------------- 1 | package com.senior.config; 2 | 3 | import java.util.HashMap; 4 | 5 | import javax.sql.DataSource; 6 | 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 9 | import org.springframework.boot.web.servlet.ServletRegistrationBean; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | 13 | import com.alibaba.druid.pool.DruidDataSource; 14 | import com.alibaba.druid.support.http.StatViewServlet; 15 | import com.alibaba.druid.support.http.WebStatFilter; 16 | 17 | @Configuration 18 | public class DruidConfig { 19 | 20 | @Bean 21 | @ConfigurationProperties(prefix = "spring.datasource") 22 | public DataSource druidDataSource() { 23 | return new DruidDataSource(); 24 | } 25 | 26 | // 监控功能 web.xml ServletRegistrationBean 27 | // 因为springboot内置了servlet容器,所以没有web.xml,替代方法 28 | 29 | @Bean 30 | public ServletRegistrationBean statViewServlet() { 31 | ServletRegistrationBean bean = new ServletRegistrationBean<>(new StatViewServlet(), 32 | "/druid/*"); 33 | 34 | // 后台需要有人登陆,账号密码配置 35 | 36 | HashMap initParameters = new HashMap<>(); 37 | // 增加配置 38 | initParameters.put("loginUsername", "root");// 登陆key是固定的 39 | initParameters.put("loginPassword", "123456"); 40 | 41 | // 允许谁能访问 42 | initParameters.put("allow", ""); 43 | 44 | bean.setInitParameters(initParameters);// 设置初始化参数 45 | return bean; 46 | } 47 | 48 | // filter 49 | @Bean 50 | public FilterRegistrationBean webStatFilter() { 51 | FilterRegistrationBean bean = new FilterRegistrationBean(); 52 | 53 | bean.setFilter(new WebStatFilter()); 54 | 55 | // 可以过滤那些请求 56 | 57 | HashMap initParameters = new HashMap<>(); 58 | 59 | // 这些东西不进行统计~ 60 | initParameters.put("exclusion", "*.js,*.css,/druid/*"); 61 | 62 | bean.setInitParameters(initParameters); 63 | return bean; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/config/Interceptor/AdminInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.senior.config.Interceptor; 2 | 3 | import java.util.Objects; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | import org.springframework.web.servlet.HandlerInterceptor; 11 | 12 | import com.senior.service.impl.UserServiceImpl; 13 | import com.senior.util.CheckToken; 14 | import com.senior.vo.TokenVo; 15 | 16 | // 管理员的拦截器 17 | @Component 18 | public class AdminInterceptor implements HandlerInterceptor { 19 | 20 | @Autowired 21 | private UserServiceImpl userService; 22 | 23 | // 这个方法是在访问接口之前执行的,我们只需要在这里写验证登陆状态的业务逻辑,就可以在用户调用指定接口之前验证登陆状态了 24 | @Override 25 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 26 | throws Exception { 27 | // 判断用户的token信息是否满足 28 | TokenVo tokenVo = new CheckToken().checkToken(request, userService); 29 | if (tokenVo != null && Objects.equals(tokenVo.getRoleId(), 3 + "")) { 30 | return true; 31 | } 32 | // 当前不满足条件,直接跳转拦截 33 | response.getWriter().print("Access denied"); 34 | return false; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/config/Interceptor/StudentInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.senior.config.Interceptor; 2 | 3 | import java.util.Objects; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | import org.springframework.web.servlet.HandlerInterceptor; 11 | 12 | import com.senior.service.impl.UserServiceImpl; 13 | import com.senior.util.CheckToken; 14 | import com.senior.vo.TokenVo; 15 | 16 | // 学生的拦截器(管理员和学生) 17 | @Component 18 | public class StudentInterceptor implements HandlerInterceptor { 19 | 20 | @Autowired 21 | private UserServiceImpl userService; 22 | 23 | // 这个方法是在访问接口之前执行的,我们只需要在这里写验证登陆状态的业务逻辑,就可以在用户调用指定接口之前验证登陆状态了 24 | @Override 25 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 26 | throws Exception { 27 | // 判断用户的token信息是否满足 28 | TokenVo tokenVo = new CheckToken().checkToken(request, userService); 29 | if (tokenVo != null 30 | && (Objects.equals(tokenVo.getRoleId(), 3 + "") || Objects.equals(tokenVo.getRoleId(), 1 + ""))) { 31 | return true; 32 | } 33 | // 当前不满足条件,直接跳转拦截 34 | response.getWriter().print("Access denied"); 35 | return false; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/config/Interceptor/TeacherInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.senior.config.Interceptor; 2 | 3 | import java.util.Objects; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | import org.springframework.web.servlet.HandlerInterceptor; 11 | 12 | import com.senior.service.impl.UserServiceImpl; 13 | import com.senior.util.CheckToken; 14 | import com.senior.vo.TokenVo; 15 | 16 | // 又属于老师又属于超级管理员和学生的拦截器 17 | @Component 18 | public class TeacherInterceptor implements HandlerInterceptor { 19 | 20 | @Autowired 21 | private UserServiceImpl userService; 22 | 23 | // 这个方法是在访问接口之前执行的,我们只需要在这里写验证登陆状态的业务逻辑,就可以在用户调用指定接口之前验证登陆状态了 24 | @Override 25 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 26 | throws Exception { 27 | // 判断用户的token信息是否满足 28 | TokenVo tokenVo = new CheckToken().checkToken(request, userService); 29 | if (tokenVo != null && (Objects.equals(tokenVo.getRoleId(), 3 + "") 30 | || Objects.equals(tokenVo.getRoleId(), 2 + "") || Objects.equals(tokenVo.getRoleId(), 1 + ""))) { 31 | return true; 32 | } 33 | // 当前不满足条件,直接跳转拦截 34 | response.getWriter().print("Access denied"); 35 | return false; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/config/Interceptor/WebAppConfigurer.java: -------------------------------------------------------------------------------- 1 | package com.senior.config.Interceptor; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 7 | 8 | @Configuration 9 | public class WebAppConfigurer implements WebMvcConfigurer { 10 | 11 | @Bean 12 | public AdminInterceptor getAdminInterceptor() {// 只属于管理员 13 | return new AdminInterceptor(); 14 | } 15 | 16 | @Bean 17 | public TeacherInterceptor getTeacherInterceptor() {// 属于老师 但是管理员也可以用 18 | return new TeacherInterceptor(); 19 | } 20 | 21 | @Bean 22 | public StudentInterceptor getStudentInterceptor() {// 属于学生 但是管理员也可以用 23 | return new StudentInterceptor(); 24 | } 25 | 26 | @Override 27 | public void addInterceptors(InterceptorRegistry registry) { 28 | // 可添加多个 29 | // 拦截未登录进入超级管理员的界面 30 | registry.addInterceptor(getAdminInterceptor()).addPathPatterns("/admin/**"); 31 | registry.addInterceptor(getTeacherInterceptor()).addPathPatterns("/teacher/**"); 32 | registry.addInterceptor(getStudentInterceptor()).addPathPatterns("/student/**"); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/config/MybatisPlusConfig.java: -------------------------------------------------------------------------------- 1 | package com.senior.config; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.annotation.Profile; 7 | 8 | import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; 9 | import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor; 10 | 11 | // 扫描我们的mapper文件夹 12 | @MapperScan("com.senior.mapper") 13 | @Configuration // 配置类 14 | public class MybatisPlusConfig { 15 | 16 | // 分页插件 17 | @Bean 18 | public PaginationInterceptor paginationInterceptor() { 19 | return new PaginationInterceptor(); 20 | } 21 | 22 | /** 23 | * SQL执行效率插件 24 | */ 25 | @Bean 26 | @Profile({"dev", "test"}) // 设置 dev test 环境开启 27 | public PerformanceInterceptor performanceInterceptor() { 28 | PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor(); 29 | performanceInterceptor.setMaxTime(1000);// ms 设置sql执行的最大时间,如果超过了则不执行 30 | performanceInterceptor.setFormat(true); 31 | return performanceInterceptor; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/config/RedisConfig.java: -------------------------------------------------------------------------------- 1 | package com.senior.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.data.redis.connection.RedisConnectionFactory; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 8 | import org.springframework.data.redis.serializer.StringRedisSerializer; 9 | 10 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 11 | import com.fasterxml.jackson.annotation.PropertyAccessor; 12 | import com.fasterxml.jackson.databind.DeserializationFeature; 13 | import com.fasterxml.jackson.databind.ObjectMapper; 14 | 15 | @Configuration 16 | public class RedisConfig { 17 | 18 | // 这是固定的模板 19 | // 自己定义了一个RedisTemplate 20 | @Bean 21 | @SuppressWarnings("all") 22 | public RedisTemplate redisTemplate(RedisConnectionFactory factory) { 23 | // 我们为了自己开发方便, 一般直接使用 24 | RedisTemplate template = new RedisTemplate(); 25 | template.setConnectionFactory(factory); 26 | 27 | // Json序列化配置 28 | Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer( 29 | Object.class); 30 | ObjectMapper om = new ObjectMapper(); 31 | om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 32 | om.activateDefaultTyping(om.getPolymorphicTypeValidator()); 33 | om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 34 | // 解决序列化问题 35 | om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 36 | jackson2JsonRedisSerializer.setObjectMapper(om); 37 | 38 | // String的序列化 39 | StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); 40 | 41 | // key采用String的序列化方式 42 | template.setKeySerializer(stringRedisSerializer); 43 | // hash的key也采用String的序列化方式 44 | template.setHashKeySerializer(stringRedisSerializer); 45 | 46 | // value序列化方式采用jackson 47 | template.setValueSerializer(jackson2JsonRedisSerializer); 48 | 49 | // hash的value序列化方式采用jackson 50 | template.setHashValueSerializer(jackson2JsonRedisSerializer); 51 | template.afterPropertiesSet(); 52 | 53 | return template; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/constant/ExamConstant.java: -------------------------------------------------------------------------------- 1 | 2 | package com.senior.constant; 3 | 4 | /** 5 | * 常量值 6 | * 7 | * @author senior 8 | */ 9 | public class ExamConstant { 10 | /** 11 | * base64图片分隔符,之所以不用逗号是因为base64默认是 data:image/png;base64, 开头,已经包含了逗号 12 | */ 13 | public static final String SEPARATOR = "list_separator"; 14 | } 15 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/controller/StudentController.java: -------------------------------------------------------------------------------- 1 | package com.senior.controller; 2 | 3 | import java.util.*; 4 | 5 | import com.senior.entity.Exam; 6 | import com.senior.service.impl.ExamServiceImpl; 7 | import com.senior.util.TokenUtils; 8 | import com.senior.vo.*; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 13 | import com.baomidou.mybatisplus.core.metadata.IPage; 14 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 15 | import com.senior.entity.ExamRecord; 16 | import com.senior.entity.User; 17 | import com.senior.service.impl.ExamRecordServiceImpl; 18 | import com.senior.service.impl.NoticeServiceImpl; 19 | import com.senior.service.impl.UserServiceImpl; 20 | 21 | import io.swagger.annotations.Api; 22 | import io.swagger.annotations.ApiImplicitParam; 23 | import io.swagger.annotations.ApiImplicitParams; 24 | import io.swagger.annotations.ApiOperation; 25 | import lombok.extern.slf4j.Slf4j; 26 | 27 | import javax.servlet.http.HttpServletRequest; 28 | 29 | @RestController 30 | @RequestMapping(value = "/student") 31 | @Slf4j 32 | @Api(tags = "学生权限相关的接口") 33 | public class StudentController { 34 | 35 | @Autowired 36 | private UserServiceImpl userService; 37 | @Autowired 38 | private ExamServiceImpl examService; 39 | @Autowired 40 | private ExamRecordServiceImpl examRecordService; 41 | 42 | @Autowired 43 | private NoticeServiceImpl noticeService; 44 | 45 | /** 46 | * @param username 系统登录用户名 47 | * @param pageNo 页面大小 48 | * @param pageSize 页面大小 49 | * @param examId 考试id 50 | * @return 51 | */ 52 | @GetMapping("/getMyGrade") 53 | @ApiOperation("获取个人成绩(分页 根据考试名查询)") 54 | @ApiImplicitParams({ 55 | @ApiImplicitParam(name = "username", value = "系统唯一用户名", required = true, dataType = "string", 56 | paramType = "query"), 57 | @ApiImplicitParam(name = "pageNo", value = "当前页面数", required = true, dataType = "int", paramType = "query"), 58 | @ApiImplicitParam(name = "pageSize", value = "当前页面大小", required = true, dataType = "int", 59 | paramType = "query"), 60 | @ApiImplicitParam(name = "examId", value = "考试唯一id", required = false, dataType = "int", 61 | paramType = "query") 62 | }) 63 | public CommonResult getMyGrade(String username, Integer pageNo, Integer pageSize, 64 | @RequestParam(required = false) Integer examId) { 65 | User user = userService.getOne(new QueryWrapper().eq("username", username)); 66 | // 参数一是当前页,参数二是每页个数 67 | IPage examRecordPage = new Page<>(pageNo, pageSize); 68 | // 查询条件(可选) 69 | QueryWrapper wrapper = new QueryWrapper<>(); 70 | wrapper.eq("user_id", user.getId()); 71 | if (examId != null) { 72 | wrapper.eq("exam_id", examId); 73 | } 74 | 75 | IPage page = examRecordService.page(examRecordPage, wrapper); 76 | List examRecords = page.getRecords(); 77 | // 创建分页结果集 78 | Map result = new HashMap<>(); 79 | result.put("examRecords", examRecords); 80 | result.put("total", examRecordPage.getTotal()); 81 | return new CommonResult<>(200, "查询成绩成功", result); 82 | } 83 | 84 | /** 85 | * @param examQueryVo 考试信息查询vo对象,可以返回当前考试是否考过 86 | * @return 87 | */ 88 | @PostMapping("/getExamInfo2") 89 | @ApiOperation("根据信息查询考试的信息") 90 | @ApiImplicitParams({ 91 | @ApiImplicitParam(name = "examQueryVo", value = "考试信息查询vo对象", required = true, dataType = "examQueryVo", 92 | paramType = "body") 93 | }) 94 | public CommonResult> getExamInfo2(@RequestBody ExamQueryVo examQueryVo, HttpServletRequest request) { 95 | 96 | String token = request.getHeader("authorization"); 97 | // 当前用户对象的信息 98 | TokenVo tokenVo = TokenUtils.verifyToken(token); 99 | User user = userService.getOne(new QueryWrapper().eq("username", tokenVo.getUsername())); 100 | 101 | 102 | log.info("执行了===>TeacherController中的getExamInfo2方法"); 103 | // 参数一是当前页,参数二是每页个数 104 | IPage examIPage = new Page<>(examQueryVo.getPageNo(), examQueryVo.getPageSize()); 105 | // 查询条件(可选) 106 | QueryWrapper wrapper = new QueryWrapper<>(); 107 | 108 | if (tokenVo != null && (Objects.equals(tokenVo.getRoleId(), 2 + ""))) { 109 | wrapper.like("create_man_id", user.getId() ); 110 | } 111 | if (tokenVo != null && (Objects.equals(tokenVo.getRoleId(), 1 + ""))) { 112 | wrapper.and(QueryWrapper -> QueryWrapper.eq("major_id", user.getMajorId() ).or().eq("major_id", 0)); 113 | 114 | wrapper.and(QueryWrapper -> QueryWrapper.like("class_name", user.getClassName() ).or().like("class_name", "全部" )); 115 | 116 | } 117 | if (examQueryVo.getClassName() != null) { 118 | 119 | wrapper.like("class_name", examQueryVo.getClassName() ); 120 | } 121 | if (examQueryVo.getMajorId() != null) { 122 | wrapper.eq("major_id", examQueryVo.getMajorId() ); 123 | } 124 | 125 | if (examQueryVo.getExamType() != null) { 126 | wrapper.eq("type", examQueryVo.getExamType()); 127 | } 128 | if (examQueryVo.getExamName() != null) { 129 | wrapper.like("exam_name", examQueryVo.getExamName()); 130 | } 131 | if (examQueryVo.getStartTime() != null) { 132 | wrapper.gt("start_time", examQueryVo.getStartTime()); 133 | } 134 | if (examQueryVo.getEndTime() != null) { 135 | wrapper.lt("end_time", examQueryVo.getEndTime()); 136 | } 137 | // 查询exam数据库表 138 | IPage page = examService.page(examIPage, wrapper); 139 | 140 | List exams = page.getRecords(); 141 | List examStates = getRecords(user, exams); 142 | return new CommonResult<>(200, "查询考试信息成功", examStates); 143 | } 144 | 145 | 146 | 147 | public List getRecords(User user, List exams) { 148 | System.out.println("f========================================"); 149 | System.out.println("==========================================="); 150 | System.out.println(exams.size()); 151 | System.out.println("f========================================"); 152 | System.out.println("==========================================="); 153 | List examStates = new ArrayList<>(); 154 | // 查询与当前用户有关的考试记录 155 | QueryWrapper wrapper = new QueryWrapper<>(); 156 | wrapper.eq("user_id", user.getId()); 157 | List records = examRecordService.list(wrapper); // 与当前用户有关的考试记录 158 | List ExamIds = new ArrayList<>(); // 与用户有关的考试id(exam_id) 159 | if(records != null) { 160 | for(int i = 0; i < records.size(); i++) { 161 | ExamIds.add(records.get(i).getExamId()); 162 | } 163 | } 164 | 165 | if(exams == null || exams.size() == 0) return examStates; 166 | // 把Exams复制给 167 | for(int i = 0; i < exams.size(); i++) { 168 | ExamState states = new ExamState(); 169 | states.setExamId(exams.get(i).getExamId()); 170 | states.setExamName(exams.get(i).getExamName()); 171 | states.setDuration(exams.get(i).getDuration()); 172 | states.setType(exams.get(i).getType()); 173 | states.setPassword(exams.get(i).getPassword()); 174 | states.setExamDesc(exams.get(i).getExamDesc()); 175 | states.setMajorId(exams.get(i).getMajorId()); 176 | states.setMajorName(exams.get(i).getMajorName()); 177 | states.setClassName(exams.get(i).getClassName()); 178 | states.setCreateMan(exams.get(i).getCreateMan()); 179 | states.setCreateManId(exams.get(i).getCreateManId()); 180 | states.setStartTime(exams.get(i).getStartTime()); 181 | states.setEndTime(exams.get(i).getEndTime()); 182 | states.setTotalScore(exams.get(i).getTotalScore()); 183 | states.setPassScore(exams.get(i).getPassScore()); 184 | if(ExamIds.contains(exams.get(i).getExamId())) { // 这个考试是考过的 185 | states.setFlag(true); 186 | }else states.setFlag(false); 187 | examStates.add(states); 188 | } 189 | return examStates; 190 | } 191 | 192 | } 193 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/controller/UtilController.java: -------------------------------------------------------------------------------- 1 | package com.senior.controller; 2 | 3 | import java.awt.image.BufferedImage; 4 | import java.io.IOException; 5 | 6 | import javax.imageio.ImageIO; 7 | import javax.servlet.http.HttpServletResponse; 8 | 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RequestParam; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import com.senior.util.CreateVerificationCode; 15 | import com.senior.vo.CommonResult; 16 | 17 | import io.swagger.annotations.Api; 18 | import io.swagger.annotations.ApiImplicitParam; 19 | import io.swagger.annotations.ApiImplicitParams; 20 | import io.swagger.annotations.ApiOperation; 21 | import lombok.extern.slf4j.Slf4j; 22 | 23 | @RestController 24 | @Slf4j 25 | @RequestMapping("/util") 26 | @Api(tags = "工具类接口") 27 | public class UtilController { 28 | 29 | static String CODE; 30 | 31 | /** 32 | * 生成随机验证码图片 33 | * 34 | * @param response 35 | * @throws IOException 36 | */ 37 | @GetMapping("/getCodeImg") 38 | @ApiOperation(value = "获取验证码图片流") 39 | @ApiImplicitParams({ 40 | @ApiImplicitParam(name = "id", value = "帮助前端生成验证码", required = false, dataType = "string", 41 | paramType = "query") 42 | }) 43 | public void getIdentifyImage(@RequestParam(required = false) String id, HttpServletResponse response) 44 | throws IOException { 45 | log.info("执行了===>UtilController中的getIdentifyImage方法"); 46 | // 设置不缓存图片 47 | response.setHeader("Pragma", "No-cache"); 48 | response.setHeader("Cache-Control", "No-cache"); 49 | response.setDateHeader("Expires", 0); 50 | // 指定生成的响应图片 51 | response.setContentType("image/jpeg"); 52 | CreateVerificationCode code = new CreateVerificationCode(); 53 | BufferedImage image = code.getIdentifyImg(); 54 | code.getG().dispose(); 55 | // 将图形验证码IO流传输至前端 56 | ImageIO.write(image, "JPEG", response.getOutputStream()); 57 | CODE = code.getCode(); 58 | } 59 | 60 | @GetMapping("/getCode") 61 | @ApiOperation(value = "获取验证码") 62 | public CommonResult getCode() { 63 | return new CommonResult<>(200, CODE); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/entity/Answer.java: -------------------------------------------------------------------------------- 1 | package com.senior.entity; 2 | 3 | import java.io.Serializable; 4 | 5 | import com.baomidou.mybatisplus.annotation.IdType; 6 | import com.baomidou.mybatisplus.annotation.TableId; 7 | import com.baomidou.mybatisplus.annotation.TableName; 8 | 9 | import io.swagger.annotations.ApiModel; 10 | import io.swagger.annotations.ApiModelProperty; 11 | import lombok.AllArgsConstructor; 12 | import lombok.Data; 13 | import lombok.NoArgsConstructor; 14 | 15 | @Data 16 | @AllArgsConstructor 17 | @NoArgsConstructor 18 | @ApiModel("答案表实体") 19 | @TableName(value = "answer") 20 | public class Answer implements Serializable { 21 | 22 | // 对应数据库的主键(uuid,自增id,雪花算法, redis,zookeeper) 23 | @TableId(type = IdType.AUTO) 24 | @ApiModelProperty(value = "主键 答案id", example = "1") 25 | private Integer id; 26 | 27 | @ApiModelProperty(value = "所有的选项信息", example = "2,3,4,5(代表ABCD四个选项)") 28 | private String allOption; 29 | 30 | @ApiModelProperty(value = "答案的图片列表", example = "img1URl, img2URl") 31 | private String images; 32 | 33 | @ApiModelProperty(value = "答案解析", example = "1+1=2") 34 | private String analysis; 35 | 36 | @ApiModelProperty(value = "问题id", example = "1") 37 | private Integer questionId; 38 | 39 | @ApiModelProperty(value = "正确的答案的索引", example = "allOption[index]") 40 | private String trueOption; 41 | 42 | } 43 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/entity/Exam.java: -------------------------------------------------------------------------------- 1 | package com.senior.entity; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | import org.springframework.format.annotation.DateTimeFormat; 7 | 8 | import com.baomidou.mybatisplus.annotation.FieldStrategy; 9 | import com.baomidou.mybatisplus.annotation.IdType; 10 | import com.baomidou.mybatisplus.annotation.TableField; 11 | import com.baomidou.mybatisplus.annotation.TableId; 12 | import com.baomidou.mybatisplus.annotation.TableName; 13 | import com.fasterxml.jackson.annotation.JsonFormat; 14 | 15 | import io.swagger.annotations.ApiModel; 16 | import io.swagger.annotations.ApiModelProperty; 17 | import lombok.AllArgsConstructor; 18 | import lombok.Data; 19 | import lombok.NoArgsConstructor; 20 | 21 | @Data 22 | @AllArgsConstructor 23 | @NoArgsConstructor 24 | @ApiModel("考试实体") 25 | @TableName(value = "exam") 26 | public class Exam implements Serializable { 27 | 28 | @ApiModelProperty(value = "主键 考试id", example = "1") 29 | @TableId(type = IdType.AUTO) 30 | private Integer examId; 31 | 32 | @ApiModelProperty(value = "考试名称", example = "小学一年级考试") 33 | private String examName; 34 | 35 | @ApiModelProperty(value = "考试描述", example = "这是一场考试的描述") 36 | private String examDesc; 37 | 38 | @ApiModelProperty(value = "考试类型1公开,2需密码", example = "1") 39 | private Integer type; 40 | 41 | @ApiModelProperty(value = "考试密码,当type=2时候存在", example = "12345") 42 | @TableField(strategy = FieldStrategy.IGNORED) 43 | private String password; 44 | 45 | @ApiModelProperty(value = "考试时间", example = "125(分钟)") 46 | private Integer duration; 47 | 48 | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 49 | @JsonFormat(shape = JsonFormat.Shape.STRING ,pattern = "yyyy-MM-dd HH:mm:ss") 50 | @ApiModelProperty(value = "考试开始时间", example = "2020-11-01 00:00:00") 51 | @TableField(strategy = FieldStrategy.IGNORED) 52 | private Date startTime; 53 | 54 | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 55 | @JsonFormat(shape = JsonFormat.Shape.STRING ,pattern = "yyyy-MM-dd HH:mm:ss") 56 | @ApiModelProperty(value = "考试结束时间", example = "2020-12-01 00:00:00") 57 | @TableField(strategy = FieldStrategy.IGNORED) 58 | private Date endTime; 59 | 60 | @ApiModelProperty(value = "考试总分", example = "100") 61 | private Integer totalScore; 62 | 63 | @ApiModelProperty(value = "考试及格线", example = "60") 64 | private Integer passScore; 65 | 66 | @ApiModelProperty(value = "考试状态 1有效 2无效", example = "1") 67 | private Integer status; 68 | 69 | 70 | @ApiModelProperty(value = "专业id") 71 | private Integer majorId; 72 | 73 | @ApiModelProperty(value = "专业名称") 74 | private String majorName; 75 | 76 | 77 | @ApiModelProperty(value = "班级名称") 78 | private String className; 79 | 80 | private String createMan; 81 | private Integer createManId; 82 | 83 | } 84 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/entity/ExamQuestion.java: -------------------------------------------------------------------------------- 1 | package com.senior.entity; 2 | 3 | import java.io.Serializable; 4 | 5 | import com.baomidou.mybatisplus.annotation.IdType; 6 | import com.baomidou.mybatisplus.annotation.TableId; 7 | import com.baomidou.mybatisplus.annotation.TableName; 8 | 9 | import io.swagger.annotations.ApiModel; 10 | import io.swagger.annotations.ApiModelProperty; 11 | import lombok.AllArgsConstructor; 12 | import lombok.Data; 13 | import lombok.NoArgsConstructor; 14 | 15 | @Data 16 | @AllArgsConstructor 17 | @NoArgsConstructor 18 | @ApiModel("考试里的题目实体") 19 | @TableName(value = "exam_question") 20 | public class ExamQuestion implements Serializable { 21 | 22 | // 对应数据库的主键(uuid,自增id,雪花算法, redis,zookeeper) 23 | @TableId(type = IdType.AUTO) 24 | @ApiModelProperty(value = "主键 考试题目表的id", example = "1") 25 | private Integer id; 26 | 27 | @ApiModelProperty(value = "问题的id字符串", example = "1,2,3") 28 | private String questionIds; 29 | 30 | @ApiModelProperty(value = "考试的id", example = "1") 31 | private Integer examId; 32 | 33 | @ApiModelProperty(value = "考试中每一题的分数", example = "1,2,3") 34 | private String scores; 35 | } 36 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/entity/ExamRecord.java: -------------------------------------------------------------------------------- 1 | package com.senior.entity; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | import org.springframework.format.annotation.DateTimeFormat; 7 | 8 | import com.baomidou.mybatisplus.annotation.IdType; 9 | import com.baomidou.mybatisplus.annotation.TableId; 10 | import com.baomidou.mybatisplus.annotation.TableName; 11 | import com.fasterxml.jackson.annotation.JsonFormat; 12 | 13 | import io.swagger.annotations.ApiModel; 14 | import io.swagger.annotations.ApiModelProperty; 15 | import lombok.AllArgsConstructor; 16 | import lombok.Data; 17 | import lombok.NoArgsConstructor; 18 | 19 | @Data 20 | @AllArgsConstructor 21 | @NoArgsConstructor 22 | @ApiModel("考试记录") 23 | @TableName(value = "exam_record") 24 | public class ExamRecord implements Serializable { 25 | @ApiModelProperty(value = "主键 考试主键的id", example = "1") 26 | @TableId(type = IdType.AUTO) 27 | private Integer recordId; 28 | 29 | @ApiModelProperty(value = "考试用户id", example = "1") 30 | private Integer userId; 31 | 32 | @ApiModelProperty(value = "用户考试中的答案", example = "1") 33 | private String userAnswers; 34 | 35 | @ApiModelProperty(value = "考试过程中的信用截图", example = "imgUrl") 36 | private String creditImgUrl; 37 | 38 | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 39 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 40 | @ApiModelProperty(value = "考试时间", example = "2020-10-20") 41 | private Date examTime; 42 | 43 | @ApiModelProperty(value = "考试逻辑得分", example = "69") 44 | private Integer logicScore; 45 | 46 | @ApiModelProperty(value = "考试的id", example = "1") 47 | private Integer examId; 48 | 49 | @ApiModelProperty(value = "考试的题目id", example = "1") 50 | private String questionIds; 51 | 52 | @ApiModelProperty(value = "考试总得分", example = "100") 53 | private Integer totalScore; 54 | 55 | @ApiModelProperty(value = "考试错题id", example = "1,2,3") 56 | private String errorQuestionIds; 57 | 58 | 59 | @ApiModelProperty(value = "专业id") 60 | private Integer majorId; 61 | 62 | @ApiModelProperty(value = "专业名称") 63 | private String majorName; 64 | 65 | private String createMan; 66 | private Integer createManId; 67 | private String className; 68 | 69 | } 70 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/entity/Major.java: -------------------------------------------------------------------------------- 1 | package com.senior.entity; 2 | 3 | 4 | import com.baomidou.mybatisplus.annotation.IdType; 5 | import com.baomidou.mybatisplus.annotation.TableId; 6 | import com.baomidou.mybatisplus.annotation.TableName; 7 | import io.swagger.annotations.ApiModel; 8 | import io.swagger.annotations.ApiModelProperty; 9 | import lombok.AllArgsConstructor; 10 | import lombok.Data; 11 | import lombok.NoArgsConstructor; 12 | 13 | import java.io.Serializable; 14 | import java.util.Date; 15 | 16 | 17 | @Data 18 | @AllArgsConstructor 19 | @NoArgsConstructor 20 | @ApiModel("专业实体") 21 | @TableName(value = "major") 22 | public class Major implements Serializable { 23 | // 对应数据库的主键(uuid,自增id,雪花算法, redis,zookeeper) 24 | @TableId(type = IdType.AUTO) 25 | @ApiModelProperty(value = "主键 id", example = "1") 26 | private Integer id; 27 | @ApiModelProperty(value = "专业名称") 28 | private String name; 29 | @ApiModelProperty(value = "创建时间") 30 | private Date createTime; 31 | } 32 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/entity/Notice.java: -------------------------------------------------------------------------------- 1 | package com.senior.entity; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | import com.baomidou.mybatisplus.annotation.IdType; 7 | import com.baomidou.mybatisplus.annotation.TableId; 8 | import com.baomidou.mybatisplus.annotation.TableName; 9 | 10 | import io.swagger.annotations.ApiModel; 11 | import io.swagger.annotations.ApiModelProperty; 12 | import lombok.AllArgsConstructor; 13 | import lombok.Data; 14 | import lombok.NoArgsConstructor; 15 | 16 | @Data 17 | @AllArgsConstructor 18 | @NoArgsConstructor 19 | @ApiModel("系统公告实体") 20 | @TableName(value = "notice") 21 | public class Notice implements Serializable { 22 | 23 | // 对应数据库的主键(uuid,自增id,雪花算法, redis,zookeeper) 24 | @TableId(type = IdType.AUTO) 25 | @ApiModelProperty(value = "主键 公告id", example = "1") 26 | private Integer nId; 27 | 28 | @ApiModelProperty(value = "公告内容(Html片段)", example = "1. 修复系统BUG") 29 | private String content; 30 | 31 | @ApiModelProperty(value = "公告创建时间", example = "2020-10-22 10:35:44") 32 | private Date createTime; 33 | 34 | @ApiModelProperty(value = "公告修改时间", example = "2020-10-22 10:35:44") 35 | private Date updateTime; 36 | 37 | @ApiModelProperty(value = "公告状态", example = "0(不是当前系统公告) 1(是当前系统公告)") 38 | private Integer status; 39 | } 40 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/entity/Question.java: -------------------------------------------------------------------------------- 1 | package com.senior.entity; 2 | 3 | import java.util.Date; 4 | 5 | import com.baomidou.mybatisplus.annotation.IdType; 6 | import com.baomidou.mybatisplus.annotation.TableId; 7 | import com.baomidou.mybatisplus.annotation.TableName; 8 | 9 | import io.swagger.annotations.ApiModel; 10 | import io.swagger.annotations.ApiModelProperty; 11 | import lombok.AllArgsConstructor; 12 | import lombok.Data; 13 | import lombok.NoArgsConstructor; 14 | 15 | @Data 16 | @AllArgsConstructor 17 | @NoArgsConstructor 18 | @ApiModel("题目实体") 19 | @TableName(value = "question") 20 | public class Question { 21 | @TableId(type = IdType.AUTO) 22 | @ApiModelProperty(value = "主键 题目id", example = "1") 23 | private Integer id; 24 | 25 | @ApiModelProperty(value = "问题内容", example = "1+1等于几") 26 | private String quContent; 27 | 28 | @ApiModelProperty(value = "创建时间") 29 | private Date createTime; 30 | 31 | @ApiModelProperty(value = "创建人的username") 32 | private String createPerson; 33 | 34 | @ApiModelProperty(value = "问题类型", example = " 1单选 2多选 3判断 4简答") 35 | private Integer quType; 36 | 37 | @ApiModelProperty(value = "问题难度", example = "1") 38 | private Integer level; 39 | 40 | @ApiModelProperty(value = "问题相关的图片", example = "imageUrl") 41 | private String image; 42 | 43 | @ApiModelProperty(value = "所属题库的id", example = "1,2") 44 | private String quBankId; 45 | 46 | @ApiModelProperty(value = "所属题库的名称", example = "小学题库") 47 | private String quBankName; 48 | 49 | @ApiModelProperty(value = "题目解析", example = "题目解析") 50 | private String analysis; 51 | private String createMan; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/entity/QuestionBank.java: -------------------------------------------------------------------------------- 1 | package com.senior.entity; 2 | 3 | import com.baomidou.mybatisplus.annotation.IdType; 4 | import com.baomidou.mybatisplus.annotation.TableId; 5 | import com.baomidou.mybatisplus.annotation.TableName; 6 | 7 | import io.swagger.annotations.ApiModel; 8 | import io.swagger.annotations.ApiModelProperty; 9 | import lombok.AllArgsConstructor; 10 | import lombok.Data; 11 | import lombok.NoArgsConstructor; 12 | 13 | @Data 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | @ApiModel("题库实体") 17 | @TableName(value = "question_bank") 18 | public class QuestionBank { 19 | 20 | @ApiModelProperty(value = "主键 题库id", example = "1") 21 | @TableId(type = IdType.AUTO) 22 | private Integer bankId; 23 | 24 | @ApiModelProperty(value = "题库名称", example = "小学数学") 25 | private String bankName; 26 | 27 | 28 | @ApiModelProperty(value = "所属专业的id", example = "1,2") 29 | private String majorId; 30 | 31 | 32 | @ApiModelProperty(value = "所属专业的") 33 | private String majorName; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.senior.entity; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | import com.baomidou.mybatisplus.annotation.IdType; 7 | import com.baomidou.mybatisplus.annotation.TableId; 8 | import com.baomidou.mybatisplus.annotation.TableName; 9 | 10 | import io.swagger.annotations.ApiModel; 11 | import io.swagger.annotations.ApiModelProperty; 12 | import lombok.AllArgsConstructor; 13 | import lombok.Data; 14 | import lombok.NoArgsConstructor; 15 | 16 | @Data 17 | @AllArgsConstructor 18 | @NoArgsConstructor 19 | @ApiModel("用户实体") 20 | @TableName(value = "user") 21 | public class User implements Serializable { 22 | 23 | // 对应数据库的主键(uuid,自增id,雪花算法, redis,zookeeper) 24 | @TableId(type = IdType.AUTO) 25 | @ApiModelProperty(value = "主键 用户id", example = "1") 26 | private Integer id; 27 | 28 | @ApiModelProperty(value = "用户角色id", example = "1(学生) 2(教师) 3(管理员)") 29 | private Integer roleId; 30 | 31 | @ApiModelProperty(value = "登录用户名") 32 | private String username; 33 | 34 | @ApiModelProperty(value = "真实姓名") 35 | private String trueName; 36 | 37 | @ApiModelProperty(value = "密码") 38 | private String password; 39 | 40 | @ApiModelProperty(value = "加密盐值") 41 | private String salt; 42 | 43 | @ApiModelProperty(value = "用户状态", example = "1正常 2禁用") 44 | private Integer status; 45 | 46 | @ApiModelProperty(value = "用户创建时间", example = "2020-10-22 10:35:44") 47 | private Date createDate; 48 | 49 | @ApiModelProperty(value = "头像") 50 | private String avatar; 51 | 52 | @ApiModelProperty(value = "专业id") 53 | private Integer majorId; 54 | 55 | @ApiModelProperty(value = "专业名称") 56 | private String majorName; 57 | 58 | 59 | @ApiModelProperty(value = "班级名称") 60 | private String className; 61 | } 62 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/entity/UserRole.java: -------------------------------------------------------------------------------- 1 | package com.senior.entity; 2 | 3 | import java.io.Serializable; 4 | 5 | import com.baomidou.mybatisplus.annotation.IdType; 6 | import com.baomidou.mybatisplus.annotation.TableId; 7 | import com.baomidou.mybatisplus.annotation.TableName; 8 | 9 | import io.swagger.annotations.ApiModel; 10 | import io.swagger.annotations.ApiModelProperty; 11 | import lombok.AllArgsConstructor; 12 | import lombok.Data; 13 | import lombok.NoArgsConstructor; 14 | 15 | @Data 16 | @AllArgsConstructor 17 | @NoArgsConstructor 18 | @ApiModel("角色实体") 19 | @TableName(value = "user_role") 20 | public class UserRole implements Serializable { 21 | // 对应数据库的主键(uuid,自增id,雪花算法, redis,zookeeper) 22 | @TableId(type = IdType.AUTO) 23 | @ApiModelProperty(value = "主键 id", example = "1") 24 | private Integer id; 25 | @ApiModelProperty(value = "角色id", example = "1(学生) 2(教师) 3(管理员)") 26 | private Integer roleId; 27 | @ApiModelProperty(value = "用户角色名称", example = "1(学生) 2(教师) 3(管理员)") 28 | private String roleName; 29 | @ApiModelProperty(value = "权限对应的功能菜单", example = "json串") 30 | private String menuInfo; 31 | } 32 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/mapper/AnswerMapper.java: -------------------------------------------------------------------------------- 1 | package com.senior.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 6 | import com.senior.entity.Answer; 7 | 8 | @Repository 9 | public interface AnswerMapper extends BaseMapper { 10 | } 11 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/mapper/ExamMapper.java: -------------------------------------------------------------------------------- 1 | package com.senior.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 6 | import com.senior.entity.Exam; 7 | 8 | // 在对应的mapper上面实现基本的接口 9 | @Repository // 代表持久层 10 | public interface ExamMapper extends BaseMapper { 11 | } 12 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/mapper/ExamQuestionMapper.java: -------------------------------------------------------------------------------- 1 | package com.senior.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 6 | import com.senior.entity.ExamQuestion; 7 | 8 | // 在对应的mapper上面实现基本的接口 9 | @Repository // 代表持久层 10 | public interface ExamQuestionMapper extends BaseMapper { 11 | } 12 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/mapper/ExamRecordMapper.java: -------------------------------------------------------------------------------- 1 | package com.senior.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 6 | import com.senior.entity.ExamRecord; 7 | 8 | // 在对应的mapper上面实现基本的接口 9 | @Repository // 代表持久层 10 | public interface ExamRecordMapper extends BaseMapper { 11 | } 12 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/mapper/MajorMapper.java: -------------------------------------------------------------------------------- 1 | package com.senior.mapper; 2 | 3 | import com.senior.entity.Major; 4 | import org.springframework.stereotype.Repository; 5 | 6 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 7 | import com.senior.entity.User; 8 | 9 | // 在对应的mapper上面实现基本的接口 10 | @Repository // 代表持久层 11 | public interface MajorMapper extends BaseMapper { 12 | } 13 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/mapper/NoticeMapper.java: -------------------------------------------------------------------------------- 1 | package com.senior.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 6 | import com.senior.entity.Notice; 7 | 8 | // 在对应的mapper上面实现基本的接口 9 | @Repository // 代表持久层 10 | public interface NoticeMapper extends BaseMapper { 11 | // 将所有公告设置为历史公告 12 | boolean setAllNoticeIsHistoryNotice(); 13 | } 14 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/mapper/QuestionBankMapper.java: -------------------------------------------------------------------------------- 1 | package com.senior.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 6 | import com.senior.entity.QuestionBank; 7 | 8 | @Repository 9 | public interface QuestionBankMapper extends BaseMapper { 10 | } 11 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/mapper/QuestionMapper.java: -------------------------------------------------------------------------------- 1 | package com.senior.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 6 | import com.senior.entity.Question; 7 | 8 | // 在对应的mapper上面实现基本的接口 9 | @Repository // 代表持久层 10 | public interface QuestionMapper extends BaseMapper { 11 | } 12 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package com.senior.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 6 | import com.senior.entity.User; 7 | 8 | // 在对应的mapper上面实现基本的接口 9 | @Repository // 代表持久层 10 | public interface UserMapper extends BaseMapper { 11 | } 12 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/mapper/UserRoleMapper.java: -------------------------------------------------------------------------------- 1 | package com.senior.mapper; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | import com.baomidou.mybatisplus.core.mapper.BaseMapper; 6 | import com.senior.entity.UserRole; 7 | 8 | // 在对应的mapper上面实现基本的接口 9 | @Repository // 代表持久层 10 | public interface UserRoleMapper extends BaseMapper { 11 | } 12 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/AnswerService.java: -------------------------------------------------------------------------------- 1 | package com.senior.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.senior.entity.Answer; 5 | 6 | public interface AnswerService extends IService { 7 | } 8 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/ExamQuestionService.java: -------------------------------------------------------------------------------- 1 | package com.senior.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.senior.entity.ExamQuestion; 5 | 6 | public interface ExamQuestionService extends IService { 7 | } 8 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/ExamRecordService.java: -------------------------------------------------------------------------------- 1 | package com.senior.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.senior.entity.ExamRecord; 5 | 6 | public interface ExamRecordService extends IService { 7 | } 8 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/ExamService.java: -------------------------------------------------------------------------------- 1 | package com.senior.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.senior.entity.Exam; 5 | 6 | public interface ExamService extends IService { 7 | } 8 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/MajorService.java: -------------------------------------------------------------------------------- 1 | package com.senior.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.senior.entity.Major; 5 | import com.senior.entity.UserRole; 6 | 7 | public interface MajorService extends IService { 8 | } 9 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/NoticeService.java: -------------------------------------------------------------------------------- 1 | package com.senior.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.senior.entity.Notice; 5 | 6 | public interface NoticeService extends IService { 7 | // 将所有公告设置为历史公告 8 | boolean setAllNoticeIsHistoryNotice(); 9 | } 10 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/QuestionBankService.java: -------------------------------------------------------------------------------- 1 | package com.senior.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.senior.entity.QuestionBank; 5 | 6 | public interface QuestionBankService extends IService { 7 | } 8 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/QuestionService.java: -------------------------------------------------------------------------------- 1 | package com.senior.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.senior.entity.Question; 5 | 6 | public interface QuestionService extends IService { 7 | } 8 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/UserRoleService.java: -------------------------------------------------------------------------------- 1 | package com.senior.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.senior.entity.UserRole; 5 | 6 | public interface UserRoleService extends IService { 7 | } 8 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.senior.service; 2 | 3 | import com.baomidou.mybatisplus.extension.service.IService; 4 | import com.senior.entity.User; 5 | 6 | public interface UserService extends IService { 7 | } 8 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/impl/AnswerServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.senior.service.impl; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 6 | import com.senior.entity.Answer; 7 | import com.senior.mapper.AnswerMapper; 8 | import com.senior.service.AnswerService; 9 | 10 | @Service 11 | public class AnswerServiceImpl extends ServiceImpl implements AnswerService { 12 | } 13 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/impl/ExamQuestionServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.senior.service.impl; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 6 | import com.senior.entity.ExamQuestion; 7 | import com.senior.mapper.ExamQuestionMapper; 8 | import com.senior.service.ExamQuestionService; 9 | 10 | @Service 11 | public class ExamQuestionServiceImpl extends ServiceImpl 12 | implements ExamQuestionService { 13 | } 14 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/impl/ExamRecordServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.senior.service.impl; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 6 | import com.senior.entity.ExamRecord; 7 | import com.senior.mapper.ExamRecordMapper; 8 | import com.senior.service.ExamRecordService; 9 | 10 | @Service 11 | public class ExamRecordServiceImpl extends ServiceImpl implements ExamRecordService { 12 | } 13 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/impl/ExamServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.senior.service.impl; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 6 | import com.senior.entity.Exam; 7 | import com.senior.mapper.ExamMapper; 8 | import com.senior.service.ExamService; 9 | 10 | @Service 11 | public class ExamServiceImpl extends ServiceImpl implements ExamService { 12 | } 13 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/impl/MajorServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.senior.service.impl; 2 | 3 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 4 | import com.senior.entity.Major; 5 | import com.senior.entity.UserRole; 6 | import com.senior.mapper.MajorMapper; 7 | import com.senior.mapper.UserRoleMapper; 8 | import com.senior.service.MajorService; 9 | import com.senior.service.UserRoleService; 10 | import org.springframework.stereotype.Service; 11 | 12 | @Service 13 | public class MajorServiceImpl extends ServiceImpl implements MajorService { 14 | } 15 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/impl/NoticeServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.senior.service.impl; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Service; 5 | 6 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 7 | import com.senior.entity.Notice; 8 | import com.senior.mapper.NoticeMapper; 9 | import com.senior.service.NoticeService; 10 | 11 | @Service 12 | public class NoticeServiceImpl extends ServiceImpl implements NoticeService { 13 | @Autowired 14 | private NoticeMapper noticeMapper; 15 | 16 | @Override 17 | public boolean setAllNoticeIsHistoryNotice() { 18 | return noticeMapper.setAllNoticeIsHistoryNotice(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/impl/QuestionBankServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.senior.service.impl; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 6 | import com.senior.entity.QuestionBank; 7 | import com.senior.mapper.QuestionBankMapper; 8 | import com.senior.service.QuestionBankService; 9 | 10 | @Service 11 | public class QuestionBankServiceImpl extends ServiceImpl 12 | implements QuestionBankService { 13 | } 14 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/impl/QuestionServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.senior.service.impl; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 6 | import com.senior.entity.Question; 7 | import com.senior.mapper.QuestionMapper; 8 | import com.senior.service.QuestionService; 9 | 10 | @Service 11 | public class QuestionServiceImpl extends ServiceImpl implements QuestionService { 12 | } 13 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/impl/UserRoleServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.senior.service.impl; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 6 | import com.senior.entity.UserRole; 7 | import com.senior.mapper.UserRoleMapper; 8 | import com.senior.service.UserRoleService; 9 | 10 | @Service 11 | public class UserRoleServiceImpl extends ServiceImpl implements UserRoleService { 12 | } 13 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.senior.service.impl; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 6 | import com.senior.entity.User; 7 | import com.senior.mapper.UserMapper; 8 | import com.senior.service.UserService; 9 | 10 | @Service 11 | public class UserServiceImpl extends ServiceImpl implements UserService { 12 | } 13 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/util/CheckToken.java: -------------------------------------------------------------------------------- 1 | package com.senior.util; 2 | 3 | import java.util.Objects; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | 7 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 8 | import com.senior.entity.User; 9 | import com.senior.service.impl.UserServiceImpl; 10 | import com.senior.vo.TokenVo; 11 | 12 | public class CheckToken { 13 | 14 | public TokenVo checkToken(HttpServletRequest request, UserServiceImpl userService) { 15 | // 获取用户的头部信息的token 16 | String token = request.getHeader("authorization"); 17 | if (token != null) { 18 | // 获取解析后的token令牌 19 | TokenVo tokenVo = TokenUtils.verifyToken(token); 20 | if (tokenVo != null) {// 解析token是否过期 21 | QueryWrapper wrapper = new QueryWrapper<>(); 22 | wrapper.eq("username", tokenVo.getUsername()); 23 | User user = userService.getOne(wrapper); 24 | // 校验token是否合法 并且是否过期 25 | if (tokenVo != null && user != null 26 | && user.getRoleId() == Integer.parseInt(tokenVo.getRoleId()) 27 | && Objects.equals(user.getPassword(), tokenVo.getPassword()) 28 | && user.getStatus() == 1) { 29 | tokenVo.setAvatar(user.getAvatar()); 30 | return tokenVo; 31 | } else {// 非法token 32 | return null; 33 | } 34 | } else { 35 | return null; 36 | } 37 | } else {// 没有token 38 | return null; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/util/CreateVerificationCode.java: -------------------------------------------------------------------------------- 1 | package com.senior.util; 2 | 3 | import java.awt.*; 4 | import java.awt.geom.Line2D; 5 | import java.awt.image.BufferedImage; 6 | import java.util.Random; 7 | 8 | import org.springframework.stereotype.Component; 9 | 10 | import lombok.Data; 11 | 12 | @Data 13 | @Component 14 | public class CreateVerificationCode { 15 | 16 | private String code; 17 | private Graphics g; 18 | 19 | /** 20 | * 获取随机生成的颜色 21 | * 22 | * @param s 23 | * @param e 24 | * @return 25 | */ 26 | public Color getRandColor(int s, int e) { 27 | 28 | Random random = new Random(); 29 | if (s > 255) { 30 | s = 91; 31 | } 32 | if (e > 255) { 33 | e = 97; 34 | } 35 | 36 | int r, g, b; 37 | r = s + random.nextInt(e - s); 38 | g = s + random.nextInt(e - s); 39 | b = s + random.nextInt(e - s); 40 | return new Color(r, g, b); 41 | 42 | } 43 | 44 | /** 45 | * 获取验证码图片 46 | */ 47 | public BufferedImage getIdentifyImg() { 48 | 49 | int width = 100; 50 | int height = 28; 51 | BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 52 | // 创建Graphics对象,相当于画笔 53 | Graphics g = image.getGraphics(); 54 | // 创建Graphics2D对象 55 | Graphics2D g2d = (Graphics2D) g; 56 | Random random = new Random(); 57 | // 定义字体样式 58 | Font font = new Font("华文宋体", Font.BOLD, 19); 59 | g.setColor(this.getRandColor(200, 250)); 60 | g.fillRect(0, 0, width, height); 61 | g.setFont(font); 62 | g.setColor(this.getRandColor(180, 200)); 63 | 64 | // 绘制100条颜色和位置全部随机的线条 该线条为2f 65 | for (int i = 0; i < 100; i++) { 66 | int x = random.nextInt(width - 1); 67 | int y = random.nextInt(height - 1); 68 | int x1 = random.nextInt(6) + 1; 69 | int y1 = random.nextInt(12) + 1; 70 | // 绘制线条样式 71 | BasicStroke bs = new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL); 72 | Line2D line = new Line2D.Double(x, y, x1 + x, y1 + y); 73 | g2d.setStroke(bs); 74 | g2d.draw(line); 75 | 76 | } 77 | 78 | // 输出由英文中文数字随机组成的验证码 79 | StringBuilder sRand = new StringBuilder(); 80 | String ctmp = ""; 81 | int itmp = 0; 82 | for (int i = 0; i < 4; i++) { 83 | switch (random.nextInt(3)) { 84 | case 1: 85 | case 2: 86 | itmp = random.nextInt(26) + 65; 87 | ctmp = String.valueOf((char) itmp); 88 | break; 89 | default: 90 | itmp = random.nextInt(10) + 48; 91 | ctmp = String.valueOf((char) itmp); 92 | break; 93 | } 94 | sRand.append(ctmp); 95 | Color color = new Color(20 + random.nextInt(110), 20 + random.nextInt(110), random.nextInt(110)); 96 | g.setColor(color); 97 | g.drawString(ctmp, 19 * i + 19, 19); 98 | } 99 | this.setCode(sRand.toString()); 100 | this.setG(g); 101 | return image; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/util/SaltEncryption.java: -------------------------------------------------------------------------------- 1 | package com.senior.util; 2 | 3 | import java.security.NoSuchAlgorithmException; 4 | import java.util.List; 5 | 6 | import org.springframework.util.DigestUtils; 7 | 8 | import com.senior.entity.Answer; 9 | 10 | public class SaltEncryption { 11 | 12 | // 盐值加密 13 | public static String saltEncryption(String password, String salt) throws NoSuchAlgorithmException { 14 | String current = password + salt; 15 | return DigestUtils.md5DigestAsHex(current.getBytes()); 16 | } 17 | 18 | // 根据题目id获取答案列表中的答案索引 19 | public static int getIndex(List list, Integer questionId) { 20 | for (int i = 0; i < list.size(); i++) { 21 | if (list.get(i).getQuestionId() == questionId) { 22 | return i; 23 | } 24 | } 25 | return -1; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/util/TokenUtils.java: -------------------------------------------------------------------------------- 1 | package com.senior.util; 2 | 3 | import java.util.Date; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import com.auth0.jwt.JWT; 8 | import com.auth0.jwt.algorithms.Algorithm; 9 | import com.auth0.jwt.interfaces.DecodedJWT; 10 | import com.auth0.jwt.interfaces.JWTVerifier; 11 | import com.senior.vo.TokenVo; 12 | 13 | public class TokenUtils {// 过期时间 14 | private static final long EXPIRE_TIME = 60 * 60 * 1000 * 5;// 默认5小时 15 | // 私钥 16 | private static final String TOKEN_SECRET = "TOKEN_SECRET"; 17 | 18 | /** 19 | * 生成token,自定义过期时间 毫秒 20 | * 21 | * @param **username** 22 | * @param **password** 23 | * @return 24 | */ 25 | public static String createToken(TokenVo token) { 26 | try { 27 | // 设置过期时间 28 | Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); 29 | // 私钥和加密算法 30 | Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); 31 | // 设置头部信息 32 | Map header = new HashMap<>(2); 33 | header.put("Type", "Jwt"); 34 | header.put("alg", "HS256"); 35 | // 返回token字符串 36 | return JWT.create() 37 | .withHeader(header) 38 | .withClaim("roleId", token.getRoleId()) 39 | .withClaim("username", token.getUsername()) 40 | .withClaim("password", token.getPassword()) 41 | .withExpiresAt(date) 42 | .sign(algorithm); 43 | } catch (Exception e) { 44 | e.printStackTrace(); 45 | return null; 46 | } 47 | } 48 | 49 | /** 50 | * 检验token是否正确 51 | * 52 | * @param **token** 53 | * @return 54 | */ 55 | public static TokenVo verifyToken(String token) { 56 | try { 57 | Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); 58 | JWTVerifier verifier = JWT.require(algorithm).build(); 59 | DecodedJWT jwt = verifier.verify(token); 60 | String roleId = jwt.getClaim("roleId").asString(); 61 | String username = jwt.getClaim("username").asString(); 62 | String password = jwt.getClaim("password").asString(); 63 | return new TokenVo(roleId, username, password); 64 | } catch (Exception e) { 65 | return null; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/vo/AddExamByBankVo.java: -------------------------------------------------------------------------------- 1 | package com.senior.vo; 2 | 3 | import java.util.Date; 4 | 5 | import io.swagger.annotations.ApiModelProperty; 6 | import org.springframework.format.annotation.DateTimeFormat; 7 | 8 | import com.fasterxml.jackson.annotation.JsonFormat; 9 | 10 | import lombok.AllArgsConstructor; 11 | import lombok.Data; 12 | import lombok.NoArgsConstructor; 13 | 14 | @Data 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | public class AddExamByBankVo { 18 | private String bankNames; 19 | 20 | private Integer examDuration; 21 | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 22 | @JsonFormat(shape = JsonFormat.Shape.STRING ,pattern = "yyyy-MM-dd HH:mm:ss") 23 | private Date startTime; 24 | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 25 | @JsonFormat(shape = JsonFormat.Shape.STRING ,pattern = "yyyy-MM-dd HH:mm:ss") 26 | private Date endTime; 27 | 28 | private String examDesc; 29 | private String examName; 30 | private Integer judgeScore; 31 | private Integer multipleScore; 32 | private Integer passScore; 33 | private Integer shortScore; 34 | private Integer singleScore; 35 | private Integer status; 36 | private Integer type; 37 | private String password; 38 | 39 | 40 | private Integer majorId; 41 | 42 | private String majorName; 43 | 44 | private String className; 45 | } 46 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/vo/AddExamByQuestionVo.java: -------------------------------------------------------------------------------- 1 | package com.senior.vo; 2 | 3 | import java.util.Date; 4 | 5 | import org.springframework.format.annotation.DateTimeFormat; 6 | 7 | import com.fasterxml.jackson.annotation.JsonFormat; 8 | 9 | import lombok.AllArgsConstructor; 10 | import lombok.Data; 11 | import lombok.NoArgsConstructor; 12 | 13 | @Data 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | public class AddExamByQuestionVo { 17 | private String examName; 18 | private String examDesc; 19 | private Integer type; 20 | private String password; 21 | private Integer examDuration; 22 | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 23 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") 24 | private Date startTime; 25 | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 26 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") 27 | private Date endTime; 28 | private Integer totalScore; 29 | private Integer passScore; 30 | private Integer status; 31 | 32 | private String questionIds; 33 | private Integer examId; 34 | private String scores; 35 | 36 | private Integer majorId; 37 | 38 | private String majorName; 39 | 40 | private String className; 41 | } 42 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/vo/BankHaveQuestionSum.java: -------------------------------------------------------------------------------- 1 | package com.senior.vo; 2 | 3 | import com.senior.entity.QuestionBank; 4 | 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | @Data 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class BankHaveQuestionSum { 13 | private QuestionBank questionBank; 14 | // 单选数量 15 | private Integer singleChoice; 16 | // 多选数量 17 | private Integer multipleChoice; 18 | // 判断数量 19 | private Integer judge; 20 | // 简答数量 21 | private Integer shortAnswer; 22 | } 23 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/vo/CommonResult.java: -------------------------------------------------------------------------------- 1 | package com.senior.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class CommonResult { 11 | private Integer code; 12 | private String message; 13 | private T data; 14 | 15 | public CommonResult(Integer code, String message) { 16 | this(code, message, null); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/vo/ExamQueryVo.java: -------------------------------------------------------------------------------- 1 | package com.senior.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class ExamQueryVo { 11 | private Integer examType; 12 | private String startTime; 13 | private String endTime; 14 | private String examName; 15 | private Integer pageNo; 16 | private Integer pageSize; 17 | 18 | private Integer majorId; 19 | 20 | private String majorName; 21 | 22 | private String className; 23 | } 24 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/vo/ExamState.java: -------------------------------------------------------------------------------- 1 | package com.senior.vo; 2 | 3 | import com.baomidou.mybatisplus.annotation.*; 4 | import com.fasterxml.jackson.annotation.JsonFormat; 5 | import io.swagger.annotations.ApiModel; 6 | import io.swagger.annotations.ApiModelProperty; 7 | import lombok.AllArgsConstructor; 8 | import lombok.Data; 9 | import lombok.NoArgsConstructor; 10 | import org.springframework.format.annotation.DateTimeFormat; 11 | 12 | import java.io.Serializable; 13 | import java.util.Date; 14 | 15 | /** 16 | * @author DingJun 17 | * @date 2022/5/16 23:42 18 | */ 19 | @Data 20 | @AllArgsConstructor 21 | @NoArgsConstructor 22 | @ApiModel("考试记录2实体") 23 | @TableName(value = "exam_state") 24 | public class ExamState implements Serializable { 25 | @ApiModelProperty(value = "主键 考试id", example = "1") 26 | @TableId(type = IdType.AUTO) 27 | private Integer examId; 28 | 29 | @ApiModelProperty(value = "考试名称", example = "小学一年级考试") 30 | private String examName; 31 | 32 | @ApiModelProperty(value = "考试描述", example = "这是一场考试的描述") 33 | private String examDesc; 34 | 35 | @ApiModelProperty(value = "考试类型1公开,2需密码", example = "1") 36 | private Integer type; 37 | 38 | @ApiModelProperty(value = "考试密码,当type=2时候存在", example = "12345") 39 | @TableField(strategy = FieldStrategy.IGNORED) 40 | private String password; 41 | 42 | @ApiModelProperty(value = "考试时间", example = "125(分钟)") 43 | private Integer duration; 44 | 45 | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 46 | @JsonFormat(shape = JsonFormat.Shape.STRING ,pattern = "yyyy-MM-dd HH:mm:ss") 47 | @ApiModelProperty(value = "考试开始时间", example = "2020-11-01 00:00:00") 48 | @TableField(strategy = FieldStrategy.IGNORED) 49 | private Date startTime; 50 | 51 | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 52 | @JsonFormat(shape = JsonFormat.Shape.STRING ,pattern = "yyyy-MM-dd HH:mm:ss") 53 | @ApiModelProperty(value = "考试结束时间", example = "2020-12-01 00:00:00") 54 | @TableField(strategy = FieldStrategy.IGNORED) 55 | private Date endTime; 56 | 57 | @ApiModelProperty(value = "考试总分", example = "100") 58 | private Integer totalScore; 59 | 60 | @ApiModelProperty(value = "考试及格线", example = "60") 61 | private Integer passScore; 62 | 63 | @ApiModelProperty(value = "考试状态 1有效 2无效", example = "1") 64 | private Integer status; 65 | 66 | 67 | @ApiModelProperty(value = "专业id") 68 | private Integer majorId; 69 | 70 | @ApiModelProperty(value = "专业名称") 71 | private String majorName; 72 | 73 | 74 | @ApiModelProperty(value = "班级名称") 75 | private String className; 76 | 77 | private String createMan; 78 | private Integer createManId; 79 | 80 | // 是否考过 true表示考过 false表示没有考过 81 | private Boolean flag; 82 | } 83 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/vo/QuestionVo.java: -------------------------------------------------------------------------------- 1 | package com.senior.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | // 前端文件上传的接受对象封装 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | public class QuestionVo { 12 | private Integer questionType; 13 | private Integer questionId; 14 | private Integer questionLevel; 15 | private Integer[] bankId; 16 | private String questionContent; 17 | private String[] images; 18 | private String analysis; 19 | private String createPerson; 20 | private Answer[] Answer; 21 | 22 | // 答案对象 23 | @Data 24 | @AllArgsConstructor 25 | @NoArgsConstructor 26 | public static class Answer { 27 | private Integer id; 28 | private String isTrue; 29 | private String answer; 30 | private String[] images; 31 | private String analysis; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /exam-admin/src/main/java/com/senior/vo/TokenVo.java: -------------------------------------------------------------------------------- 1 | package com.senior.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class TokenVo { 11 | private String roleId; 12 | private String username; 13 | private String password; 14 | private String avatar; 15 | 16 | public TokenVo(String roleId, String username, String password) { 17 | this.roleId = roleId; 18 | this.username = username; 19 | this.password = password; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /exam-admin/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8888 3 | 4 | spring: 5 | servlet: 6 | multipart: 7 | # 最大文件大小 8 | max-file-size: 10MB 9 | # 最大请求大小 10 | max-request-size: 10MB 11 | # json序列化date类型时候防止出现 T 12 | jackson: 13 | date-format: yyyy-MM-dd HH:mm:ss 14 | time-zone: GMT+8 15 | redis: 16 | host: localhost 17 | port: 6379 18 | datasource: 19 | username: root 20 | password: 6807234 21 | url: jdbc:mysql://localhost:3306/exam?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true 22 | driver-class-name: com.mysql.jdbc.Driver 23 | type: com.alibaba.druid.pool.DruidDataSource 24 | # 数据源其他配置 25 | initialSize: 5 26 | minIdle: 5 27 | maxActive: 20 28 | maxWait: 60000 29 | timeBetweenEvictionRunsMillis: 60000 30 | minEvictableIdleTimeMillis: 300000 31 | validationQuery: SELECT 1 FROM DUAL 32 | testWhileIdle: true 33 | testOnBorrow: false 34 | testOnReturn: false 35 | poolPreparedStatements: true 36 | # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 37 | filters: stat,wall,log4j 38 | maxPoolPreparedStatementPerConnectionSize: 20 39 | useGlobalDataSourceStat: true 40 | connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500 41 | 42 | mybatis-plus: 43 | mapper-locations: classpath:mapper/*.xml 44 | type-aliases-package: com.senior.entity 45 | configuration: 46 | # 配置日志 47 | log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 48 | -------------------------------------------------------------------------------- /exam-admin/src/main/resources/mapper/MajorMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /exam-admin/src/main/resources/mapper/NoticeMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | update notice 7 | set status = 0; 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /exam-admin/src/main/resources/mapper/UserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /exam-admin/src/main/resources/mapper/UserRoleMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /exam-vue/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /exam-vue/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js, jsx, ts, tsx, vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /exam-vue/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | 4 | env: { 5 | node: true 6 | }, 7 | 8 | extends: [ 9 | 'plugin:vue/essential', 10 | '@vue/standard' 11 | ], 12 | 13 | parserOptions: { 14 | parser: 'babel-eslint' 15 | }, 16 | 17 | rules: { 18 | 'no-console': 'off', 19 | 'no-debugger': 'off' 20 | }, 21 | 22 | extends: [ 23 | 'plugin:vue/essential', 24 | '@vue/standard' 25 | ], 26 | 27 | 'extends': [ 28 | 'plugin:vue/strongly-recommended', 29 | '@vue/standard' 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /exam-vue/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /exam-vue/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ], 5 | plugins: [ 6 | [ 7 | 'component', 8 | { 9 | libraryName: 'element-ui', 10 | styleLibraryName: 'theme-chalk' 11 | } 12 | ] 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /exam-vue/debug.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/exam-vue/debug.log -------------------------------------------------------------------------------- /exam-vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "exam-vue", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.20.0", 12 | "core-js": "^3.6.5", 13 | "echarts": "^4.9.0", 14 | "element-ui": "^2.4.5", 15 | "node-sass": "^4.14.1", 16 | "nprogress": "^0.2.0", 17 | "sass-loader": "^10.0.3", 18 | "vue": "^2.6.11", 19 | "vue-router": "^3.2.0", 20 | "wangeditor": "^4.6.6" 21 | }, 22 | "devDependencies": { 23 | "@vue/cli-plugin-babel": "~4.5.0", 24 | "@vue/cli-plugin-eslint": "~4.5.0", 25 | "@vue/cli-plugin-router": "~4.5.0", 26 | "@vue/cli-service": "~4.5.0", 27 | "@vue/eslint-config-standard": "^5.1.2", 28 | "babel-eslint": "^10.1.0", 29 | "babel-plugin-component": "^1.1.1", 30 | "eslint-plugin-import": "^2.20.2", 31 | "eslint-plugin-node": "^11.1.0", 32 | "eslint-plugin-promise": "^4.2.1", 33 | "eslint-plugin-standard": "^4.0.0", 34 | "eslint-plugin-vue": "^6.2.2", 35 | "vue-cli-plugin-element": "^1.0.1", 36 | "vue-template-compiler": "^2.6.11" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /exam-vue/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/exam-vue/public/favicon.ico -------------------------------------------------------------------------------- /exam-vue/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 在线考试系统 10 | 11 | 12 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /exam-vue/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | 12 | 22 | -------------------------------------------------------------------------------- /exam-vue/src/api/api.js: -------------------------------------------------------------------------------- 1 | let API = { 2 | //应用表 3 | api: { 4 | // 查询应用列表 5 | register: '/common/register', 6 | //查询当前的验证码 7 | getCode: '/util/getCode', 8 | //校验用户名 9 | checkUsername: '/common/check', 10 | //登陆接口 11 | login: '/common/login', 12 | //获取主页面的左侧menu数据 13 | getMenuInfo: '/common/getMenu', 14 | //检验token合法(返回当前对象) 15 | checkToken: '/common/checkToken', 16 | //用户退出登录 17 | logout: '/common/logout', 18 | //获取用户信息(可附带查询条件,可分页,n功能合一接口) 19 | getUserInfo: '/admin/getUser', 20 | //管理员操作用户 21 | handleUser: '/admin/handleUser', 22 | //管理员新增用户 23 | addUser: '/admin/addUser', 24 | //获取角色信息 25 | getRoleInfo: '/admin/getRole', 26 | //获取所有题库信息 27 | getQuestionBank: '/teacher/getQuestionBank', 28 | //获取题目信息(可附带查询条件,可分页,n功能合一接口) 29 | getQuestion: '/teacher/getQuestion', 30 | getQuestion2: '/teacher/getQuestion2', 31 | //批量删除题目 32 | deleteQuestion: '/teacher/deleteQuestion', 33 | //将题目加入进题库 34 | addBankQuestion: '/teacher/addBankQuestion', 35 | //将题目从题库中移除 36 | removeBankQuestion: '/teacher/removeBankQuestion', 37 | //填加题目中的上传图片 38 | uploadQuestionImage: '/common/image/upload', 39 | //添加题目 40 | addQuestion: '/teacher/addQuestion', 41 | //根据题目id查询题目信息 42 | getQuestionById: '/teacher/getQuestionById', 43 | getQuestionByIds: '/teacher/getQuestionByIds', 44 | //根据题目id更新题目信息 45 | updateQuestion: '/teacher/updateQuestion', 46 | //查询所有题库信息和里面含有的题目类型的数量 47 | getBankHaveQuestionSumByType: '/teacher/getBankHaveQuestionSumByType', 48 | //删除题库及去除所有包含题库信息的题目 49 | deleteQuestionBank: '/teacher/deleteQuestionBank', 50 | //添加题库信息 51 | addQuestionBank: '/teacher/addQuestionBank', 52 | //根据题库id查询题库信息 53 | getBankById: '/teacher/getBankById', 54 | //根据题库id查询题库中所有单选 多选 判断题 55 | getQuestionByBank: '/teacher/getQuestionByBank', 56 | //根据题库id查询各种类型的题目 57 | getQuestionByBankIdAndType: '/teacher/getQuestionByBankIdAndType', 58 | //查询考试信息 59 | getExamInfo: '/teacher/getExamInfo', 60 | // 查询考试加是否已考信息 61 | getExamInfo2: 'student/getExamInfo2', 62 | //对考试信息操作 63 | operationExam: '/teacher/operationExam', 64 | //根据题库添加考试 65 | addExamByBank: '/teacher/addExamByBank', 66 | //根据题目列表添加考试 67 | addExamByQuestionList: '/teacher/addExamByQuestionList', 68 | //根据考试id查询考试信息和题目信息 69 | getExamInfoById: '/teacher/getExamInfoById', 70 | //更新考试的规则信息 71 | updateExamInfo: '/teacher/updateExamInfo', 72 | //新增考试记录 73 | addExamRecord: '/teacher/addExamRecord', 74 | //根据考试记录的id查询考试记录信息 75 | getExamRecordById: '/teacher/getExamRecordById', 76 | //根据考试id查询考试中的每一道题目id和分值 77 | getExamQuestionByExamId: '/teacher/getExamQuestionByExamId', 78 | //根据考试记录id查询考试的信息 79 | getExamRecord: '/teacher/getExamRecord', 80 | //根据考试id单纯的查询考试对象信息 81 | getExamById: '/teacher/getExamById', 82 | //教师用户根据用户id查询用户 83 | getUserById: '/teacher/getUserById', 84 | //查询所有的考试信息 85 | allExamInfo: '/teacher/allExamInfo', 86 | //批阅试卷的客观题 87 | setObjectQuestionScore: '/teacher/setObjectQuestionScore', 88 | //查询当前用户的信息 89 | getCurrentUser: '/common/getCurrentUser', 90 | //更新当前用户的信息 91 | updateCurrentUser: '/common/updateCurrentUser', 92 | //获取我的成绩(根据username) 93 | getMyGrade: '/student/getMyGrade', 94 | //获取考试通过率(echarts绘图) 95 | getExamPassRate: '/teacher/getExamPassRate', 96 | //获取考试的次数(echarts绘图) 97 | getExamNumbers: '/teacher/getExamNumbers', 98 | //获取所有系统公告信息 99 | getAllNotice: '/admin/getAllNotice', 100 | //获取最新的系统公告 101 | getCurrentNewNotice: '/common/getCurrentNewNotice', 102 | //发布公告 103 | publishNotice: '/admin/publishNotice', 104 | //批量删除公告 105 | deleteNotice: '/admin/deleteNotice', 106 | //更新公告 107 | updateNotice: '/admin/updateNotice', 108 | //获取专业信息 109 | getMajorInfo: '/admin/getMajor', 110 | //添加专业信息 111 | addMajor: '/admin/addMajor', 112 | //获取所有专业信息 113 | getMajorBank: '/common/getMajorBank', 114 | //更改题库名称 115 | updateBankName: '/common/updateBankName', 116 | // 重置用户密码 117 | resetPwd: '/admin/updatePwd', 118 | // 校验题库 119 | checkBank: '/common/checkBank', 120 | //根据用户id和考试id查询考试 121 | checkExam: 'student/getExamRecordByUser', 122 | }, 123 | } 124 | 125 | export default { 126 | API: API, 127 | } 128 | -------------------------------------------------------------------------------- /exam-vue/src/assets/css/global.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | padding: 0; 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | p { 9 | padding: 0 !important; 10 | margin: 0 !important; 11 | font-size: 15px; 12 | } 13 | 14 | span { 15 | font-weight: 200; 16 | } 17 | 18 | .el-table td, .el-table th.is-leaf { 19 | border-bottom: none; 20 | } 21 | 22 | .el-message-box { 23 | width: 50% !important; 24 | } 25 | -------------------------------------------------------------------------------- /exam-vue/src/assets/imgs/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/exam-vue/src/assets/imgs/bg.png -------------------------------------------------------------------------------- /exam-vue/src/assets/imgs/examTitle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/exam-vue/src/assets/imgs/examTitle.png -------------------------------------------------------------------------------- /exam-vue/src/assets/imgs/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/exam-vue/src/assets/imgs/favicon.png -------------------------------------------------------------------------------- /exam-vue/src/assets/imgs/judge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/exam-vue/src/assets/imgs/judge.png -------------------------------------------------------------------------------- /exam-vue/src/assets/imgs/multiple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/exam-vue/src/assets/imgs/multiple.png -------------------------------------------------------------------------------- /exam-vue/src/assets/imgs/order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/exam-vue/src/assets/imgs/order.png -------------------------------------------------------------------------------- /exam-vue/src/assets/imgs/random.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/exam-vue/src/assets/imgs/random.png -------------------------------------------------------------------------------- /exam-vue/src/assets/imgs/single.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/exam-vue/src/assets/imgs/single.png -------------------------------------------------------------------------------- /exam-vue/src/assets/imgs/true.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/exam-vue/src/assets/imgs/true.png -------------------------------------------------------------------------------- /exam-vue/src/assets/imgs/wellcome.5bb22a17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/exam-vue/src/assets/imgs/wellcome.5bb22a17.jpg -------------------------------------------------------------------------------- /exam-vue/src/assets/imgs/wellcome.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/exam-vue/src/assets/imgs/wellcome.jpg -------------------------------------------------------------------------------- /exam-vue/src/assets/imgs/wellcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/exam-vue/src/assets/imgs/wellcome.png -------------------------------------------------------------------------------- /exam-vue/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/exam-vue/src/assets/logo.png -------------------------------------------------------------------------------- /exam-vue/src/components/Dashboard.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 19 | 20 | 50 | -------------------------------------------------------------------------------- /exam-vue/src/components/ExamManage.vue: -------------------------------------------------------------------------------- 1 | 143 | 144 | 323 | 324 | 345 | -------------------------------------------------------------------------------- /exam-vue/src/components/ExamOnline.vue: -------------------------------------------------------------------------------- 1 | 137 | 138 | 302 | 303 | 347 | -------------------------------------------------------------------------------- /exam-vue/src/components/ExamResult.vue: -------------------------------------------------------------------------------- 1 | 96 | 97 | 209 | 210 | 315 | -------------------------------------------------------------------------------- /exam-vue/src/components/Login.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 174 | 175 | 237 | -------------------------------------------------------------------------------- /exam-vue/src/components/Major.vue: -------------------------------------------------------------------------------- 1 | 71 | 72 | 179 | 180 | 212 | -------------------------------------------------------------------------------- /exam-vue/src/components/MarkExamPage.vue: -------------------------------------------------------------------------------- 1 | 99 | 100 | 243 | 244 | 349 | -------------------------------------------------------------------------------- /exam-vue/src/components/MarkManage.vue: -------------------------------------------------------------------------------- 1 | 98 | 99 | 199 | 200 | 245 | -------------------------------------------------------------------------------- /exam-vue/src/components/MyGrade.vue: -------------------------------------------------------------------------------- 1 | 136 | 137 | 261 | 262 | 363 | -------------------------------------------------------------------------------- /exam-vue/src/components/MyQuestionBank.vue: -------------------------------------------------------------------------------- 1 | 143 | 144 | 291 | 292 | 378 | 379 | -------------------------------------------------------------------------------- /exam-vue/src/components/Register.vue: -------------------------------------------------------------------------------- 1 | 68 | 69 | 221 | 222 | 281 | -------------------------------------------------------------------------------- /exam-vue/src/components/RoleManage.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 62 | 63 | 95 | -------------------------------------------------------------------------------- /exam-vue/src/components/StatisticOverview.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 214 | 215 | 237 | -------------------------------------------------------------------------------- /exam-vue/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import './plugins/element.js' 5 | import axios from 'axios' 6 | import api from './api/api' 7 | // 引入echarts 8 | import echarts from 'echarts' 9 | //解决路径跳转的报错 10 | import Router from 'vue-router' 11 | import ElementUI from 'element-ui' 12 | 13 | Vue.prototype.$echarts = echarts 14 | Vue.use(ElementUI) 15 | 16 | 17 | //配置请求根路径 18 | axios.defaults.baseURL = 'http://localhost:8888/' 19 | //axios拦截器拦截每一个请求,有token就配置头信息的token 20 | axios.interceptors.request.use(config => { 21 | let token = window.localStorage.getItem('authorization') 22 | if (token) { // 判断是否存在token,如果存在的话,则每个http header都加上token 23 | config.headers.authorization = token 24 | } 25 | return config 26 | }, error => { 27 | return Promise.reject(error) 28 | }) 29 | 30 | //接口地址统一管理 31 | Vue.prototype.API = api.API.api 32 | /** 33 | * 原型链挂载 34 | * @type {AxiosStatic} 35 | */ 36 | Vue.prototype.$http = axios 37 | Vue.config.productionTip = false 38 | 39 | //全局过滤器(秒数转化为分钟) 40 | Vue.filter('timeFormat', function (time) { 41 | //分钟 42 | var minute = time / 60; 43 | var minutes = parseInt(minute); 44 | 45 | if (minutes < 10) { 46 | minutes = "0" + minutes; 47 | } 48 | 49 | //秒 50 | var second = time % 60; 51 | var seconds = Math.round(second); 52 | if (seconds < 10) { 53 | seconds = "0" + seconds; 54 | } 55 | return `${minutes}:${seconds}`; 56 | }) 57 | 58 | const originalPush = Router.prototype.push 59 | Router.prototype.push = function push(location) { 60 | return originalPush.call(this, location).catch(err => err) 61 | } 62 | 63 | new Vue({ 64 | router, 65 | render: h => h(App) 66 | }).$mount('#app') 67 | -------------------------------------------------------------------------------- /exam-vue/src/plugins/element.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { 3 | Alert, 4 | Aside, 5 | Breadcrumb, 6 | BreadcrumbItem, 7 | Button, 8 | Card, 9 | Checkbox, 10 | CheckboxGroup, 11 | Col, 12 | Container, 13 | DatePicker, 14 | Dialog, 15 | Dropdown, 16 | DropdownItem, 17 | DropdownMenu, 18 | Footer, 19 | Form, 20 | FormItem, 21 | Header, 22 | Input, 23 | InputNumber, 24 | Loading, 25 | Main, 26 | Menu, 27 | MenuItem, 28 | MenuItemGroup, 29 | Message, 30 | MessageBox, 31 | Notification, 32 | Option, 33 | Pagination, 34 | Radio, 35 | RadioGroup, 36 | Row, 37 | Scrollbar, 38 | Select, 39 | Step, 40 | Steps, 41 | Submenu, 42 | Table, 43 | TableColumn, 44 | Tag, 45 | Tooltip, 46 | Upload 47 | } from 'element-ui' 48 | 49 | Vue.prototype.$message = Message 50 | Vue.prototype.$alert = MessageBox.alert 51 | Vue.prototype.$notify = Notification 52 | Vue.prototype.$confirm = MessageBox.confirm 53 | Vue.prototype.$prompt = MessageBox.prompt 54 | Vue.prototype.$Loading = Loading 55 | 56 | Vue.use(Button) 57 | Vue.use(Scrollbar) 58 | Vue.use(InputNumber) 59 | Vue.use(Alert) 60 | Vue.use(RadioGroup) 61 | Vue.use(Steps) 62 | Vue.use(Step) 63 | Vue.use(Radio) 64 | Vue.use(DatePicker) 65 | Vue.use(CheckboxGroup) 66 | Vue.use(Checkbox) 67 | Vue.use(Upload) 68 | Vue.use(Dialog) 69 | Vue.use(Loading) 70 | Vue.use(Pagination) 71 | Vue.use(Option) 72 | Vue.use(Select) 73 | Vue.use(Tag) 74 | Vue.use(Table) 75 | Vue.use(TableColumn) 76 | Vue.use(DropdownMenu) 77 | Vue.use(DropdownItem) 78 | Vue.use(Dropdown) 79 | Vue.use(Container) 80 | Vue.use(BreadcrumbItem) 81 | Vue.use(Tooltip) 82 | Vue.use(Main) 83 | Vue.use(Row) 84 | Vue.use(Footer) 85 | Vue.use(Card) 86 | Vue.use(FormItem) 87 | Vue.use(Form) 88 | Vue.use(Input) 89 | Vue.use(Aside) 90 | Vue.use(Menu) 91 | Vue.use(Col) 92 | Vue.use(MenuItem) 93 | Vue.use(MenuItemGroup) 94 | Vue.use(Header) 95 | Vue.use(Submenu) 96 | Vue.use(Breadcrumb) 97 | -------------------------------------------------------------------------------- /exam-vue/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import axios from 'axios' 4 | 5 | import NProgress from 'nprogress' // Progress 进度条 6 | import 'nprogress/nprogress.css' // Progress 进度条样式 7 | // 进度条配置项 8 | NProgress.configure({ 9 | showSpinner: false 10 | }); 11 | 12 | Vue.use(VueRouter) 13 | 14 | const routes = [ 15 | { 16 | path: '/', 17 | component: () => import('../components/Login') 18 | }, 19 | { 20 | path: '/register', 21 | component: () => import('../components/Register') 22 | }, 23 | { 24 | path: '/index', 25 | component: () => import('../components/Main'), 26 | redirect: '/dashboard', 27 | children: [ 28 | //仪表盘介绍(all) 29 | { 30 | path: '/dashboard', 31 | component: () => import('../components/Dashboard') 32 | }, 33 | //用户管理(超级管理员) 34 | { 35 | path: '/userManage', 36 | component: () => import('../components/UserManage') 37 | }, 38 | //角色信息(超级管理员) 39 | { 40 | path: '/roleManage', 41 | component: () => import('../components/RoleManage') 42 | }, 43 | //题库管理(老师和超级管理员) 44 | { 45 | path: '/questionManage', 46 | component: () => import('../components/QuestionManage') 47 | }, 48 | //题库管理(老师和超级管理员) 49 | { 50 | path: '/questionBankMange', 51 | component: () => import('../components/QuestionBankManage') 52 | }, 53 | //我的题库(all) 54 | { 55 | path: '/myQuestionBank', 56 | component: () => import('../components/MyQuestionBank') 57 | }, 58 | //题库训练页(学生和管理员) 59 | { 60 | path: '/train/:bankId/:trainType', 61 | name: 'trainPage', 62 | component: () => import('../components/TrainPage') 63 | }, 64 | //考试管理(老师和超级管理员) 65 | { 66 | path: '/examManage', 67 | component: () => import('../components/ExamManage') 68 | }, 69 | //添加考试(老师和超级管理员) 70 | { 71 | path: '/addExam', 72 | component: () => import('../components/AddExam') 73 | }, 74 | //修改考试信息(老师和超级管理员) 75 | { 76 | path: '/updateExam/:examId', 77 | name: 'updateExam', 78 | component: () => import('../components/UpdateExam') 79 | }, 80 | //在线考试页面选择考试(学生和超级管理员) 81 | { 82 | path: '/examOnline', 83 | component: () => import('../components/ExamOnline') 84 | }, 85 | //考试结果页(学生和超级管理员) 86 | { 87 | path: '/examResult/:recordId', 88 | name: 'examResult', 89 | component: () => import('../components/ExamResult') 90 | }, 91 | //阅卷管理页面(老师和超级管理员) 92 | { 93 | path: '/markManage', 94 | component: () => import('../components/MarkManage') 95 | }, 96 | //批阅试卷(老师和管理员) 97 | { 98 | path: '/markExam/:recordId', 99 | name: 'markExam', 100 | component: () => import('../components/MarkExamPage') 101 | }, 102 | //我的成绩(学生和管理员) 103 | { 104 | path: '/myGrade', 105 | component: () => import('../components/MyGrade') 106 | }, 107 | //统计总览页面(老师和管理员) 108 | { 109 | path: '/staticOverview', 110 | component: () => import('../components/StatisticOverview') 111 | }, 112 | // 公告管理(管理员) 113 | { 114 | path: '/noticeManage', 115 | component: () => import('../components/NoticeManage') 116 | }, 117 | // 专业(管理员) 118 | { 119 | path: '/major', 120 | component: () => import('../components/Major') 121 | }, 122 | { 123 | path: '/questionTk/:bankName/:bankId/', 124 | component: () => import('../components/QuestionTk') 125 | } 126 | ] 127 | }, 128 | //考试界面(管理员和学生) 129 | { 130 | path: '/exam/:examId', 131 | name: 'exam', 132 | component: () => import('../components/ExamPage') 133 | } 134 | ] 135 | 136 | const router = new VueRouter({ 137 | routes 138 | }) 139 | router.beforeEach((to, from, next) => { 140 | NProgress.start(); 141 | const token = window.localStorage.getItem('authorization') 142 | //2个不用token的页面请求 143 | if (to.path === '/' || to.path === '/register') { 144 | return next() 145 | } 146 | //没有token的情况 直接返回登录页 147 | if (!token) return next('/') 148 | //属于超级管理员的功能 149 | if (to.path === '/userManage' || to.path === '/roleManage' || to.path === '/noticeManage'|| to.path === '/major') { 150 | axios.get('/common/checkToken').then((resp) => { 151 | if (resp.data.code === 200 && resp.data.data.roleId === '3') {//当前用户携带的token信息正确并且是管理员 152 | next() 153 | } else { 154 | return next('/index') 155 | } 156 | }) 157 | } 158 | //属于超级管理员又属于老师 159 | if (to.path === '/questionManage' || to.path === '/questionBankMange' || to.path === '/examManage' 160 | || to.path === '/addExam' || to.name === 'updateExam' || to.path === '/markManage' || to.name === 'markExam') { 161 | axios.get('/common/checkToken').then((resp) => { 162 | if (resp.data.code === 200 && resp.data.data.roleId === '3' || resp.data.data.roleId === '2') { 163 | next() 164 | } else { 165 | return next('/index') 166 | } 167 | }) 168 | } 169 | 170 | //超级管理员 + 学生 171 | if (to.path === '/myQuestionBank' || to.name === 'trainPage' || to.path === '/examOnline' 172 | || to.name === 'exam' || to.name === 'examResult' || to.path === '/myGrade') { 173 | axios.get('/common/checkToken').then((resp) => { 174 | if (resp.data.code === 200 && resp.data.data.roleId !== '2') { 175 | next() 176 | } else { 177 | return next('/index') 178 | } 179 | }) 180 | } 181 | next() 182 | }) 183 | 184 | router.afterEach(() => { 185 | NProgress.done() // 结束Progress 186 | }); 187 | 188 | export default router 189 | -------------------------------------------------------------------------------- /exam-vue/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lintOnSave: false 3 | } 4 | -------------------------------------------------------------------------------- /初始用户1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/初始用户1.png -------------------------------------------------------------------------------- /初始用户2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/初始用户2.png -------------------------------------------------------------------------------- /在线考试系统设计文档.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/在线考试系统设计文档.pdf -------------------------------------------------------------------------------- /说明.txt: -------------------------------------------------------------------------------- 1 | 解压exam.rar文件: 2 | exam-vue 前端项目 3 | exam-admin 后端项目 4 | sql/exam.sql 数据库初始化执行文件 mysql数据库 用户root 密码6807234 5 | 分别启动exam-vue和exam-admin项目,按照开发环境手册指示 6 | 7 | 8 | http://82.157.164.123/ 建议通过服务器ip地址访问 9 | 10 | 用户密码默认为123456 -------------------------------------------------------------------------------- /项目开发环境手册.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moon-Light404/ExamOnline/ce22e9031baa7bdb196f85b2250b826bdf8468a7/项目开发环境手册.pdf --------------------------------------------------------------------------------