日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

在线考试系统(微服务,前后端分离)

發布時間:2024/3/12 windows 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 在线考试系统(微服务,前后端分离) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前臺代碼

?👉manager-protal


后臺代碼

?👉 ? manager-service


視頻演示

?👉b站視頻


項目基本功能

?本在線考試系統主要完成了

  • 用戶注冊,根據用戶名和密碼實現注冊
  • 用戶登錄,分為賬號密碼登錄,短信登錄,郵箱登錄
  • 用戶信息完善,用戶基本信息填寫(頭像,名稱,年齡,地區,學號,手機號,郵箱號)。
  • 用戶信息搜索,根據輸入的關鍵字進行信息檢索,查看用戶的數據。可以通過聚合條件檢索。管理員可以查看完整數據和統計信息。
  • 用戶管理,管理員可以查看用戶的相關數據,并進行管理員的分配。
  • 考生管理,管理員考生考試的管理,可以查看考生考試的信息,考生試卷,重置試卷,再次考試,無條件刪除考生訂閱信息。
  • 學科管理,管理員可以查看所有學科信息,添加學科,修改學科信息,刪除(是否啟用)學科。
  • 試題管理,管理員可以查看所有試題信息,添加試題,修改試題信息,刪除(是否啟用)學科。
  • 試卷管理,管理員可以查看所有試卷信息,添加試卷,修改試卷信息,刪除(是否啟用)試卷。可以預覽試卷,并且可以選擇是否發布試卷。
  • 考試管理,發布好的試卷會進入考試管理,管理員可以為試卷設置考試試卷,取消試卷發布和預覽試卷。
  • 答題管理,管理員可以查看每個試題的答題情況,并進行答題情況統計(答題人數,答題總數,錯誤率)
  • 考試訂閱,考生可以查看已經發布了的考試,可以訂閱已發布并且設置了考試時間的考試,并且有條件的刪除訂閱
  • 在線考試答題,考生可以查看已訂閱的考試信息,答題次數,并且進行答題,考完之后可以查看試卷和分數,有條件的刪除訂閱。
  • 成績查詢,考生可以查看訂閱試卷的基本信息,分數以及答題次數。
  • 單個考生的數據統計,考生可以查看自己不同學科的近6次考試情況的統計,考試試卷分布圖,學科考試次數比例圖,不同學科的答題數。
  • 全部考生的數據統計,管理員可以查看全部考生不同學科的近20次考試情況的統計,考試試卷分布圖,學科考試次數比例圖,不同學科的答題數。
  • 用戶數據統計,管理員可以查看全部用戶的地理分布情況,不同年齡的用戶數量分布,近6個月的用戶注冊數和平均年齡。
  • 日志管理,管理員可以查看關于考試的日志記錄。


  • 系統架構

    ?在線考試系統主要采用Vue+SpringBoot+SpringCloud+Mybatis框架開發。內部采用標準的MVC架構進行基本框架搭建。通過Ngnix進行反向代理,服務器采用Docker進行統一管理,使用FastDFS完成遠程的文件上傳。具體的使用技術請看👉技術選型





    技術選型

    前臺

    技術介紹
    HTML,CSS,LESSemm…沒什么好說的
    Vue.js2.6項目的前臺是完全基于Vue進行搭建的
    Npm前端安裝包工具
    Webpack前端模塊打包工具
    Vue-cliVue的腳手架,用于構建基本項目架構
    Vue-routerVue的路由工具
    VuexVue的狀態管理模式,集中式存儲管理
    Element-uiVue的一些基本組件庫
    axiosajax的框架,用于異步請求
    v-charts構建統計視圖
    vue-quill-editor基于Vue的富文本框架
    vue-particles粒子特效

    后臺

    介紹
    SpringBoot該項目每個微服務內部都是使用SpringBoot進行搭建的,emmm,直接牛逼
    SpringCloud該項目是由好幾個微服務組成的,微服務之間的注冊和調用等是通過SpringCloud來完成的。使用到了Eureka,Zuul,Ribbon,Feign
    MybatisPlus該項目使用MybatisPlus來完成對mysql的持久層操作
    SpringData該項目雖然沒有使用JPA來完成對mysql的操作,但是其他數據庫(MongoDB,redis,ElasticSearch)都是使用SpringData來操作的
    JWT該項目用jwt實現單點登錄,對用戶的請求進行認證。采用的是無狀態登錄
    Rsa一個非對稱機密算法,將token的載荷和秘鑰進行加密放入簽名域
    FastDFS一個輕量級的分布式文件系統,用于項目上傳圖片等文件
    RabbitMQ該技術是基于AMQP協議的消息代理軟件,通過該技術實現了手機,驗證碼的發送以及數據庫之間數據的同步
    Mysql該項目用Mysql來存儲主要的數據(用戶信息,學科信息,發布的試卷信息,用戶訂閱的考試信息,用戶的考試親狂)
    MD5一個不可逆加密算法,該項目用md5來實現對用戶密碼的加密
    Druid該項目使用Druid來作為mysql的數據源
    MongoDB該項目用MongoDB來存儲關于試卷的數據(試題信息,試卷信息)以及日志信息
    ElasticSearch該項目用ElasticSearch來存儲用于搜索的用戶數據,并實現搜索和聚合等功能
    Redis該項目用Redis來做部分數據的緩存,并且用redis來存儲手機和郵箱的驗證碼信息
    Nginx該項目用Nginx來實現反向代理
    Quartz定時任務框架,該項目用Quartz來實現某些操作的定
    Swagger2該項目用swagger2實現對RESTful風格的api進行統一描述和可視化調用
    Lombok該項目使用Lombok來簡化實體類和日志
    Logback該項目使用logback來實現日志的輸出和持久化
    Hibernate-validator該項目使用hibernate-validator來進行部分實體類的數據校驗
    Docker該項目使用的服務器是用docker進行統一管理的
    阿里云短信服務服務該項目使用的短信服務是由阿里云提供的
    Git該項目用git來進行版本管理

    其實,我這個項目不應該使用JWT完成單點登錄的,最好是使用SpringSecurity和OAuth2來完成權限和登錄的控制,一開始對項目的整體預估不足,貪圖簡單,就直接使用了JWT+Rsa來寫了,寫到后來權限控制那塊很難控制了,無奈呀~。沒辦法,都成型了,也懶得重構了,這個項目就這樣吧。下次注意!



    項目目錄框架

    前臺


    后臺


    單微服務目錄框架

    這里已考試微服務為例

    用戶微服務介紹

    數據庫

    CREATE TABLE `tb_user` (`id` bigint(64) NOT NULL COMMENT '雪花算法生成id',`name` varchar(10) DEFAULT NULL COMMENT '用戶的名稱',`age` int(3) DEFAULT '0' COMMENT '用戶的年齡',`area_province` varchar(10) DEFAULT NULL COMMENT '用戶的地區-省',`area_city` varchar(10) DEFAULT NULL COMMENT '用戶的地區-市',`area_county` varchar(10) DEFAULT NULL COMMENT '用戶的地區-縣',`status` tinyint(1) NOT NULL COMMENT '是否為管理員,1是,0不是',`username` varchar(32) NOT NULL COMMENT '用戶名',`sno` varchar(32) DEFAULT NULL COMMENT '用戶的學號',`password` varchar(32) NOT NULL COMMENT '密碼,加密存儲',`phone` varchar(11) DEFAULT NULL COMMENT '用戶的手機號',`email` varchar(50) DEFAULT NULL COMMENT '用戶的郵箱',`image` varchar(100) DEFAULT NULL COMMENT '用戶的頭像地址',`created` datetime NOT NULL COMMENT '創建時間',`salt` varchar(32) NOT NULL COMMENT '密碼加密的salt值',`version` bigint(20) DEFAULT '0' COMMENT '版本,樂觀鎖',`deleted` tinyint(1) DEFAULT '0' COMMENT '邏輯刪除,1刪除,0沒刪除',PRIMARY KEY (`id`),UNIQUE KEY `username` (`username`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶表';

    API


    手機,郵箱驗證碼獲取接口

    ?這里就兩個接口,一個是獲取手機驗證碼,一個是獲取郵箱驗證碼

    • 手機驗證碼通過rabbitmq發送驗證碼,并且設置2分鐘的過期時期保存在redis中

      //發送消息 this.amqpTemplate.convertAndSend(this.authCodeProperties.getExchangeName(), "authCode.phone", authInfo);//將驗證碼放入redis中 this.redisTemplate.opsForValue().set(this.authCodeProperties.getPhoneName()+phone,authcode,2, TimeUnit.MINUTES);
    • 郵箱驗證碼通過rabbitmq發送驗證碼,并且設置2分鐘的過期時期保存在redis中

      //發送消息 this.amqpTemplate.convertAndSend(this.authCodeProperties.getExchangeName(), "authCode.email", authInfo);//將驗證碼放入redis中 this.redisTemplate.opsForValue().set(this.authCodeProperties.getEmailName()+email,authcode,2, TimeUnit.MINUTES);

    ?👉 點擊查看rabbitmq接受消息代碼

    用戶基本的DML操作服務接口

    ?DML操作無非就是贈刪改操作,但是看我們的API接口卻并沒有DELETE的操作,這是為什么呢?

    ?仔細看我們的用戶數據庫表,我是使用的邏輯刪除!


    剩下的接口就不說了


    考試微服務介紹

    數據庫

    學科表

    CREATE TABLE `tb_subject` (`id` bigint(64) NOT NULL COMMENT '雪花算法生成id',`name` varchar(10) DEFAULT NULL COMMENT '學科的名稱',`note` varchar(100) DEFAULT NULL COMMENT '學科的備注信息',`icon` varchar(50) NOT NULL COMMENT '學科的圖標',`index` varchar(100) NOT NULL COMMENT '學科的前臺路徑',`created` datetime NOT NULL COMMENT '創建時間',`version` bigint(20) DEFAULT '0' COMMENT '版本,樂觀鎖',`deleted` tinyint(1) DEFAULT '0' COMMENT '邏輯刪除,1刪除,0沒刪除',PRIMARY KEY (`id`),UNIQUE KEY `name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='學科表';

    試題表

    試題的信息是存放在MongoDB中的

    • select:是用于存儲選擇題的選項的,判斷題不存在
    • answer:試題的正確答案索引
    • type:試題的類型,0:選擇題,1:判斷題
    • subject:學科的id
    • note:試題的備注信息

    試卷表

    試卷的信息也是存放在MongoDB中的

    • name: 試卷名字
    • subject:試卷的學科id
    • school:出題學校的名字
    • creatoe:出題人的用戶名(用戶名不可變)
    • astrict:試卷的答題限制時間
    • select:選擇題的題目id
    • judge:判斷題的題目id
    • selectScore:每到選擇題的分數
    • judgeScore:每到判斷題的分數
    • note:備注信息
    • publicsh:是否發布

    發布試卷記錄表

    CREATE TABLE `tb_public_test` (`id` bigint(64) NOT NULL COMMENT '雪花算法生成id',`test_id` varchar(100) NOT NULL COMMENT '試卷的id',`start_time` timestamp NOT NULL DEFAULT '2020-01-01 00:00:00' COMMENT '試卷的開始時間',`end_time` timestamp NOT NULL DEFAULT '2020-01-01 00:00:00' COMMENT '試卷的結束時間',`status` int(3) NOT NULL COMMENT '試卷的狀態,-2:已刪除,-1:初始化,0:未開始,1:開啟中,2:已結束',`created` datetime NOT NULL COMMENT '創建時間',`version` bigint(20) DEFAULT '0' COMMENT '版本,樂觀鎖',`deleted` tinyint(1) DEFAULT '0' COMMENT '邏輯刪除,1刪除,0沒刪除',PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='試卷發布狀態表';

    我給start_time和end_time設置了一個過去的初始化時間

    用戶訂閱試卷表

    CREATE TABLE `tb_subscribe_exam` (`id` bigint(64) NOT NULL COMMENT '雪花算法生成id',`user_id` bigint(64) NOT NULL COMMENT '訂閱的用戶id',`test_id` varchar(100) NOT NULL COMMENT '試卷的id',`status` int(3) DEFAULT '0' COMMENT '訂閱記錄的狀態0:未考試,1:正在考試,2:已考試,3:再次考試',`score` double(6,1) DEFAULT '0.0' COMMENT '試卷的分數',`begin_work_time` timestamp NOT NULL DEFAULT '2020-01-01 00:00:00' COMMENT '開始答題時間',`finish_work_time` timestamp NOT NULL DEFAULT '2020-01-01 00:00:00' COMMENT '結束答題時間',`frequency` int(3) DEFAULT '0' COMMENT '考試的次數',`created` datetime NOT NULL COMMENT '創建時間',`version` bigint(20) DEFAULT '0' COMMENT '版本,樂觀鎖',`deleted` tinyint(1) DEFAULT '0' COMMENT '邏輯刪除,1刪除(取消訂閱后的狀態),0沒刪除(點擊訂閱后的狀態)',PRIMARY KEY (`id`),KEY `user_id` (`user_id`),CONSTRAINT `tb_subscribe_exam_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `tb_user` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶訂閱試卷表';

    試題答題情況表

    CREATE TABLE `tb_exam_answer_situation` (`id` bigint(64) NOT NULL COMMENT '雪花算法生成id',`subscribe_exam_id` bigint(64) NOT NULL COMMENT '訂閱的考試id',`topic_id` varchar(100) NOT NULL COMMENT '試題id',`user_answer` varchar(200) NOT NULL COMMENT '用戶的答案,-1為未答題',`answer_situation` int(3) NOT NULL COMMENT '用戶的答題情況。-1:未答題,0:答錯,1:答對',`score` double(6,1) DEFAULT '0.0' COMMENT '試題的得分',`created` datetime NOT NULL COMMENT '創建時間',`version` bigint(20) DEFAULT '0' COMMENT '版本,樂觀鎖',`deleted` tinyint(1) DEFAULT '0' COMMENT '邏輯刪除,1刪除,0沒刪除',PRIMARY KEY (`id`),KEY `subscribe_exam_id` (`subscribe_exam_id`),CONSTRAINT `tb_exam_answer_situation_ibfk_1` FOREIGN KEY (`subscribe_exam_id`) REFERENCES `tb_subscribe_exam` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶答題具體情況';

    用戶每一個答題都會生成一條記錄,與訂閱試卷表示一對多的關系


    日志記錄表

    用于記錄用戶,管理員的一些試卷操作。(比如:答題,取消試卷訂閱,重置試卷等)

    API

    Api以及具體的實現代碼太多了,就不多說了

    消息服務介紹

    以手機驗證碼為例

    @RabbitListener(bindings = @QueueBinding(value = @Queue(value="MANAGER_PHONE_SMS_QUEUE",durable = "true"),exchange = @Exchange(value="MANAGER_EXCHANGE_SMS",ignoreDeclarationExceptions = "true",type=ExchangeTypes.TOPIC),key = "authCode.phone" )) public void sendPhoneAuthCode(Map<String,String> msg) throws ClientException {if(CollectionUtils.isEmpty(msg)){return ;}String phone = msg.get("phone");String authcode = msg.get("authcode");//放棄處理if(StringUtils.isAllBlank(phone,authcode)){return ;}log.info("接收到 {} 的驗證碼 {},準備發送",phone,authcode);if(!StringUtils.isEmpty(phone)&&!StringUtils.isEmpty(authcode)) {JsonObject jsonObject = new JsonObject();jsonObject.addProperty("authcode", authcode);this.sendPhoneSmsUtils.sendSms(phone,jsonObject.toString(),this.smsProperties.getSignName(),this.smsProperties.getVerifyCodeTemplate());} }
    • 當接收到數據時,會對數據進行一個簡單的空判斷,復雜的判斷在前臺和傳遞數據的時候已經校驗過了
    • 數據沒問題,就會調用阿里云的手機驗證碼服務,對對應的手機號發送驗證碼

    上傳微服務

    • 上傳圖像回顯url,并修改數據庫
    public String uploadImage(MultipartFile file) {String originName=file.getOriginalFilename();//驗證文件類型String contentType=file.getContentType();if(!uploadProperties.getContentTypes().contains(contentType)){//使用日志記錄不合法的信息log.info("文件類型不合法: {}",originName);return null;}try {//校驗文件的內容BufferedImage bufferedImage= ImageIO.read(file.getInputStream());if(bufferedImage==null){log.info("文件的內容不合法: {}",originName);return null;}//獲取文件類型String suffix=StringUtils.substringAfterLast(originName,".");//保存到服務器StorePath storePath=fastFileStorageClient.uploadFile(file.getInputStream(),file.getSize(),suffix,null);//返回url,進行回顯String url=uploadProperties.getImageUrl()+storePath.getFullPath();log.info("上傳成功: {},帶分組路徑: {}",originName,url);//修改用戶信息this.userClient.updateImage(url);return url;} catch (IOException e){log.info("服務器內部錯誤,圖片上傳失敗:{}",originName);e.printStackTrace();}return null;}
    • 上傳縮略圖
    StorePath storePath=this.fastFileStorageClient.uploadImageAndCrtThumbImage(file.getInputStream(),file.getSize(),suffix,null);String thumbImagePath =uploadProperties.getImageUrl()+storePath.getGroup()+"/"+thumbImageConfig.getThumbImagePath(storePath.getPath());

    搜索微服務

    API

    加一個搜索查詢API


    監聽

    /*** @Description 接受新增和修改用戶信息的消息* @date 2020/7/17 23:30* @param id* @return void*/ @RabbitListener(bindings = @QueueBinding(value=@Queue(value="MANAGER.SEARCH.SAVE.QUEUE",durable = "true"),exchange = @Exchange(value="MANAGER.EXCANGE.USER.SEARCH",ignoreDeclarationExceptions = "true",type = ExchangeTypes.TOPIC),key = {"user.insert","user.update"} )) public void save(Long id){if(id==null){throw new NullPointerException("新增(更新)檢索用戶信息的id為空");}this.userSearchService.save(id); }/*** @Description 接受刪除用戶信息的消息* @date 2020/7/17 23:31* @param id* @return void*/ @RabbitListener(bindings = @QueueBinding(value=@Queue(value="MANAGER.SEARCH.DELETE.QUEUE",durable = "true"),exchange = @Exchange(value="MANAGER.EXCANGE.USER.SEARCH",ignoreDeclarationExceptions = "true",type = ExchangeTypes.TOPIC),key = {"item.delete"} )) public void delete(Long id){if(id==null){throw new NullPointerException("刪除檢索用戶信息的id為空");}this.userSearchService.delete(id); }

    當新增,修改,刪除用戶時,會通知ElasticSearch進行數據修改,是數據庫信息同步


    服務

    /*** @author codekiller* @date 2020/7/16 20:17* @Description 用戶的搜索服務接口*/ public interface IUserSearchService {/*** @Description 構建用戶數據* @date 2020/7/17 20:18* @param user* @return top.codekiller.manager.search.pojo.UserInfo*/UserInfo buildUserInfo(User user);/*** @Description 檢索* @date 2020/7/17 21:20* @param searchRequest* @return top.codekiller.manager.search.pojo.result.user.SearchResult*/SearchResult search(SearchRequest searchRequest);/*** @Description 存儲新的用戶信息和更新* @date 2020/7/17 22:36* @param id* @return void*/void save(Long id);/*** @Description 刪除用戶信息* @date 2020/7/17 22:36* @param id* @return void*/void delete(Long id); }

    一共四個服務,就是增刪改查!




    ps:

    ?項目有很多的不足,有很多都是應該好好完善的和修改的,我也懶得再去修改和重構了。因為是第一次完全靠自己寫一個項目,很多規范一開始做的不是很好。

    ?當在寫上傳和用戶等微服務時,很多東西沒有注意到,比如就說權限管理那塊;還有狀態碼相關,一開始全部用的自帶狀態碼,用來用去發現就那幾個…😒,后來大部分用得都是自建狀態碼。還有異常處理,實在懶得去做太多處理了,一個字:就是懶!封裝做的也不是太好!

    ?索性在寫試卷微服務時,有了一定的改善,代碼規范稍微好了一點,也有了一定的套路。但還是有很大的不足。

    ?怎么說呢,因為有期末考試的緣故,也花了好長時間去復習,所以斷斷續續做了一個多月。習慣了寫后端,這個前臺也確實花了我不少時間,也是第一次完全用Vue去構建前臺,雖然也有些不規范,并且很多功能沒有去添加。但是做下來,也算有所收獲吧。那就不虧!

    ?不知道下次要多久再去構建這么一個完整項目了,今年要多學些技術,明年就要考研了,一切都要時間,都需要去慢慢磨。這是一次不算很好,但也絕對不糟糕的體驗,以后會繼續努力!

    總結

    以上是生活随笔為你收集整理的在线考试系统(微服务,前后端分离)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。