• 基于Spring Boot+MyBatis+MySQL的高校试卷管理系统


    目录

    一、 系统背景和意义 1
    (一) 系统背景 1
    (二) 系统意义 1
    二、 系统技术 2
    (一) SpringBoot 2
    (二) MySQL 2
    (三) MyBatis 2
    三、 系统需求分析 3
    (一) 数据库需求 3
    (二) 系统功能需求 3
    (三) 性能需求 3
    (四) 系统流程图 4
    四、 系统设计 5
    (一) 数据库设计 5
    (二) 系统设计 9
    五、 系统实现 16
    (一) 登录界面 16
    (二) 注册界面 16
    (三) 管理员主页 17
    (四) 学生主页 17
    (五) 学生在线考试面板 18
    (六) 学生成绩查询面板 18
    (七) 管理员题库管理面板 19
    (八) 管理员考试管理面板 19
    六、 系统测试 20
    (一) 功能测试概要 21
    (二) 测试环境与配置 21
    (三) 机器配置 22
    (四) 基础数据准备 23
    (五) 功能测试 23
    (六) 系统检测记录 24
    (七) 测试结果说明 22
    二、系统技术
    (一)SpringBoot
    Spring Boot从根本上讲其实就是一些maven库的集合,在maven系统中导入相应依赖即可使用Spring Boot,而且无需自行管理这些库的版本。
    (二)MySQL
    SQL(Structured Query Language):是一种结构化查询语言,用于访问和处理关系型数据库系统的计算机标准语言。为系统提供数据存储和管理的功能,以便我们更好地管理和存储师生信息
    (三)MyBatis
    MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
    三、系统需求分析
    (一)数据库需求
    对于数据库,我们需要设计一个能够容纳整个学校的师生信息的数据库并且可以实现增删改查的功能;还能够写入学生的成绩信息等。
    (二)系统功能需求
    对于系统的功能,我们需要设计登录、注册、考试、自动阅卷、管理学生信息、记录信息等功能。
    (三)性能需求
    对性能要求比较严格,因为在考试期间需要系统可以让所有学生同时登陆系统进行在线考试,并且实时记录学生的考试信息,在考试结束后及时发布考试成绩信息,并且记录下相关信息录入到数据库中。本文转载自http://www.biyezuopin.vip/onews.asp?id=15619

    package com.yf.exam.aspect;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONArray;
    import com.alibaba.fastjson.JSONObject;
    import com.baomidou.mybatisplus.core.metadata.IPage;
    import com.fasterxml.jackson.annotation.JsonFormat;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.yf.exam.core.annon.Dict;
    import com.yf.exam.core.api.ApiRest;
    import com.yf.exam.core.utils.BeanMapper;
    import com.yf.exam.core.utils.Reflections;
    import com.yf.exam.modules.sys.system.service.SysDictService;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StringUtils;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.ParameterizedType;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    /**
     * 数据字典AOP类,处理数据字典值
     * @author bool
     */
    @Aspect
    @Component
    @Slf4j
    public class DictAspect {
    
        @Autowired
        private SysDictService sysDictService;
    
        /**
         * 切入Controller
         */
        @Pointcut("execution(public *  com.yf.exam.modules..*.*Controller.*(..))")
        public void execService() {
        }
    
        @Around("execService()")
        public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
            long time1 = System.currentTimeMillis();
            Object result = pjp.proceed();
            long time2 = System.currentTimeMillis();
            log.error("获取JSON数据 耗时:" + (time2 - time1) + "ms");
            long start = System.currentTimeMillis();
            this.parseAllDictText(result);
            long end = System.currentTimeMillis();
            log.error("解析注入JSON数据  耗时" + (end - start) + "ms");
            return result;
        }
    
        /**
         * 转换全部数据字典
         * @param result
         */
        private void parseAllDictText(Object result) {
    
            // 非ApiRest类型不处理
            if (result instanceof ApiRest) {
                parseFullDictText(result);
            }
        }
    
    
        /**
         * 转换所有类型的数据字典、包含子列表
         * @param result
         */
        private void parseFullDictText(Object result) {
    
            try {
    
                // 分页的
                if (((ApiRest) result).getData() instanceof IPage) {
                    List<JSONObject> items = new ArrayList<>(16);
                    for (Object record : ((IPage) ((ApiRest) result).getData()).getRecords()) {
                        JSONObject item = this.parseObject(record);
                        items.add(item);
                    }
                    ((IPage) ((ApiRest) result).getData()).setRecords(items);
                    return;
                }
    
                // 数据列表的
                if (((ApiRest) result).getData() instanceof List) {
                    List<JSONObject> items = new ArrayList<>();
                    for (Object record : ((List) ((ApiRest) result).getData())) {
                        JSONObject item = this.parseObject(record);
                        items.add(item);
                    }
                    // 重新回写值
                    ((ApiRest) result).setData(items);
                    return;
                }
    
                // 处理单对象
                JSONObject item = this.parseObject(((ApiRest) result).getData());
                ((ApiRest) result).setData(item);
    
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    
        /**
         * 处理数据字典值
         * @param record
         * @return
         */
        public JSONObject parseObject(Object record) {
    
            if(record == null){
                return null;
            }
    
            log.info("++++++++++翻译字典:"+ JSON.toJSONString(record));
    
            ObjectMapper mapper = new ObjectMapper();
            String json = "{}";
            try {
                //解决@JsonFormat注解解析不了的问题详见SysAnnouncement类的@JsonFormat
                json = mapper.writeValueAsString(record);
            } catch (JsonProcessingException e) {
                log.error("json解析失败" + e.getMessage(), e);
            }
            JSONObject item = JSONObject.parseObject(json);
            for (Field field : Reflections.getAllFields(record)) {
                // 如果是List类型
                if(List.class.isAssignableFrom(field.getType())){
                    try {
                        List<JSONObject> list = this.processList(field, item.getJSONArray(field.getName()));
                        item.put(field.getName(), list);
                        continue;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
    
                // 处理普通字段
                if (field.getAnnotation(Dict.class) != null) {
                    String code = field.getAnnotation(Dict.class).dicCode();
                    String text = field.getAnnotation(Dict.class).dicText();
                    String table = field.getAnnotation(Dict.class).dictTable();
                    String key = String.valueOf(item.get(field.getName()));
    
                    //翻译字典值对应的txt
                    String textValue = this.translateDictValue(code, text, table, key);
                    if(StringUtils.isEmpty(textValue)){
                        textValue = "";
                    }
                    item.put(field.getName() + "_dictText", textValue);
                }
    
                //日期格式转换
                if (field.getType().getName().equals("java.util.Date")
                        && field.getAnnotation(JsonFormat.class) == null
                        && item.get(field.getName()) != null) {
                    SimpleDateFormat aDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    item.put(field.getName(), aDate.format(new Date((Long) item.get(field.getName()))));
                }
            }
    
            return item;
        }
    
        /**
         * 获得类型为List的值
         * @param field
         * @return
         */
        private List<JSONObject> processList(Field field, JSONArray array) throws IllegalAccessException, InstantiationException {
    
            // 空判断
            if(array == null || array.size()==0){
                return new ArrayList<>();
            }
    
            // 获得List属性的真实类
            ParameterizedType pt = (ParameterizedType) field.getGenericType();
            Class clazz = (Class) pt.getActualTypeArguments()[0];
    
            // 返回列表
            List<JSONObject> list = new ArrayList<>(16);
    
            for(int i=0; i<array.size(); i++){
                // 创建实例-->赋值-->字典处理
                Object data = clazz.newInstance();
                BeanMapper.copy(array.get(i), data);
                JSONObject obj = this.parseObject(data);
                list.add(obj);
            }
            return list;
        }
    
        /**
         * 翻译字典文本
         *
         * @param code
         * @param text
         * @param table
         * @param key
         * @return
         */
        private String translateDictValue(String code, String text, String table, String key) {
            if (StringUtils.isEmpty(key)) {
                return null;
            }
    
            try {
                StringBuffer textValue = new StringBuffer();
                String[] keys = key.split(",");
                for (String k : keys) {
                    String tmpValue = null;
                    log.debug(" 字典 key : " + k);
                    if (k.trim().length() == 0) {
                        continue; //跳过循环
                    }
    
                    if (!StringUtils.isEmpty(table)) {
                        log.debug("--DictAspect------dicTable=" + table + " ,dicText= " + text + " ,dicCode=" + code);
                        tmpValue = sysDictService.findDict(table, text, code, k.trim());
                    }
    
                    if (tmpValue != null) {
                        if (!"".equals(textValue.toString())) {
                            textValue.append(",");
                        }
                        textValue.append(tmpValue);
                    }
    
                }
                return textValue.toString();
            }catch (Exception e){
                e.printStackTrace();
            }
    
            return "";
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    屏幕宽度获取
    算法常用 C++ 容器总结
    本地跟单EA安装教程详解
    [C++数据结构](31)哈夫曼树,哈夫曼编码与解码
    坚持了 10 年的 9 个编程好习惯
    分享一个java+springboot+vue校园电动车租赁系统(源码、调试、开题、lw)
    2023年天津农学院专升本招生专业及报考专业限制范围的通知
    SpringBoot SpringBoot 运维实用篇 1 打包与运行 1.2 打包插件
    线性回归实现原理
    谈谈你对 AQS 的理解
  • 原文地址:https://blog.csdn.net/newlw/article/details/126686228