From 6b3a6217b89f03640065b66444b1c6aa123eb99d Mon Sep 17 00:00:00 2001 From: ovo Date: Sun, 30 Mar 2025 20:32:16 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20[=E4=B8=B4=E6=97=B6=E6=8F=90=E4=BA=A4]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deps.txt | 455 +++++++++++++++ logs/backend.log.0 | 6 + logs/backend.log.1 | 6 + pom.xml | 122 ++++ readme.md | 10 +- .../com/guwan/backend/BackendApplication.java | 3 +- .../java/com/guwan/backend/VideoDuration.java | 28 + .../backend/aspect/OperationLogAspect.java | 1 + .../backend/constant/CacheConstants.java | 2 +- .../java/com/guwan/backend/controller/Ac.java | 15 + .../backend/controller/CommonController.java | 156 +++++ .../backend/controller/CompileResult.java | 27 + .../backend/controller/CoursesController.java | 17 +- .../backend/controller/DemoController.java | 3 - .../backend/controller/DockerController.java | 222 +++++++- .../backend/controller/DockerCppRunner.java | 79 +++ .../guwan/backend/controller/TestCase.java | 13 + .../com/guwan/backend/core/BeanMapper.java | 59 ++ .../com/guwan/backend/core/annon/Dict.java | 21 + .../com/guwan/backend/core/api/ApiError.java | 67 +++ .../com/guwan/backend/core/api/ApiRest.java | 64 +++ .../core/api/controller/BaseController.java | 154 +++++ .../guwan/backend/core/api/dto/BaseDTO.java | 15 + .../backend/core/api/dto/BaseIdReqDTO.java | 27 + .../backend/core/api/dto/BaseIdRespDTO.java | 25 + .../backend/core/api/dto/BaseIdsReqDTO.java | 25 + .../backend/core/api/dto/BaseStateReqDTO.java | 31 + .../backend/core/api/dto/PagingReqDTO.java | 47 ++ .../backend/core/api/dto/PagingRespDTO.java | 30 + .../backend/core/api/utils/JsonConverter.java | 48 ++ .../guwan/backend/core/enums/CommonState.java | 19 + .../guwan/backend/core/enums/OpenType.java | 18 + .../core/exception/ServiceException.java | 52 ++ .../exception/ServiceExceptionHandler.java | 47 ++ .../guwan/backend/core/utils/CronUtils.java | 31 + .../guwan/backend/core/utils/DateUtils.java | 103 ++++ .../com/guwan/backend/core/utils/IpUtils.java | 65 +++ .../guwan/backend/core/utils/Reflections.java | 319 +++++++++++ .../guwan/backend/core/utils/SpringUtils.java | 32 ++ .../guwan/backend/core/utils/StringUtils.java | 39 ++ .../backend/core/utils/excel/ExportExcel.java | 391 +++++++++++++ .../backend/core/utils/excel/ImportExcel.java | 305 ++++++++++ .../utils/excel/annotation/ExcelField.java | 59 ++ .../core/utils/excel/fieldtype/ListType.java | 57 ++ .../backend/core/utils/file/Md5Util.java | 37 ++ .../core/utils/passwd/PassHandler.java | 58 ++ .../backend/core/utils/passwd/PassInfo.java | 38 ++ .../backend/face/entity/UserCompareInfo.java | 3 +- .../backend/face/enums/ErrorCodeEnum.java | 3 +- .../backend/face/face/FaceRecognize.java | 5 +- .../face/factory/FaceEngineFactory.java | 7 +- .../face/rpc/GlobalExceptionHandler.java | 11 +- .../face/service/FaceEngineService.java | 7 +- .../service/impl/FaceEngineServiceImpl.java | 15 +- .../backend/mapper/BSCategoryMapper.java | 2 + .../guwan/backend/mapper/CoursesMapper.java | 2 + .../guwan/backend/mapper/PapersMapper.java | 2 + .../guwan/backend/mapper/QuestionsMapper.java | 2 + .../model/exam/controller/ExamController.java | 70 +++ .../guwan/backend/model/exam/dto/ExamDTO.java | 103 ++++ .../backend/model/exam/dto/ExamDepartDTO.java | 33 ++ .../backend/model/exam/dto/ExamRepoDTO.java | 51 ++ .../model/exam/dto/ext/ExamRepoExtDTO.java | 33 ++ .../exam/dto/request/ExamSaveReqDTO.java | 33 ++ .../exam/dto/response/ExamOnlineRespDTO.java | 23 + .../exam/dto/response/ExamReviewRespDTO.java | 32 ++ .../guwan/backend/model/exam/entity/Exam.java | 101 ++++ .../backend/model/exam/entity/ExamDepart.java | 50 ++ .../backend/model/exam/entity/ExamRepo.java | 78 +++ .../backend/model/exam/enums/ExamState.java | 33 ++ .../model/exam/mapper/ExamDepartMapper.java | 16 + .../backend/model/exam/mapper/ExamMapper.java | 32 ++ .../model/exam/mapper/ExamRepoMapper.java | 27 + .../model/exam/service/ExamDepartService.java | 26 + .../model/exam/service/ExamRepoService.java | 30 + .../model/exam/service/ExamService.java | 34 ++ .../service/impl/ExamDepartServiceImpl.java | 45 ++ .../service/impl/ExamRepoServiceImpl.java | 39 ++ .../exam/service/impl/ExamServiceImpl.java | 77 +++ .../paper/controller/PaperController.java | 171 ++++++ .../backend/model/paper/dto/PaperDTO.java | 80 +++ .../model/paper/dto/PaperQuAnswerDTO.java | 48 ++ .../backend/model/paper/dto/PaperQuDTO.java | 54 ++ .../paper/dto/ext/PaperQuAnswerExtDTO.java | 29 + .../model/paper/dto/ext/PaperQuDetailDTO.java | 33 ++ .../paper/dto/request/PaperAnswerDTO.java | 22 + .../paper/dto/request/PaperCreateReqDTO.java | 22 + .../paper/dto/request/PaperListReqDTO.java | 39 ++ .../paper/dto/request/PaperQuQueryDTO.java | 21 + .../paper/dto/response/ExamDetailRespDTO.java | 39 ++ .../paper/dto/response/ExamResultRespDTO.java | 19 + .../paper/dto/response/PaperListRespDTO.java | 27 + .../backend/model/paper/entity/Paper.java | 125 ++++ .../backend/model/paper/entity/PaperQu.java | 80 +++ .../model/paper/entity/PaperQuAnswer.java | 68 +++ .../backend/model/paper/enums/ExamState.java | 33 ++ .../backend/model/paper/enums/PaperState.java | 33 ++ .../backend/model/paper/job/BreakExamJob.java | 45 ++ .../model/paper/mapper/PaperMapper.java | 40 ++ .../paper/mapper/PaperQuAnswerMapper.java | 27 + .../model/paper/mapper/PaperQuMapper.java | 42 ++ .../paper/service/PaperQuAnswerService.java | 45 ++ .../model/paper/service/PaperQuService.java | 71 +++ .../model/paper/service/PaperService.java | 84 +++ .../impl/PaperQuAnswerServiceImpl.java | 62 ++ .../service/impl/PaperQuServiceImpl.java | 95 ++++ .../paper/service/impl/PaperServiceImpl.java | 537 ++++++++++++++++++ .../model/qu/controller/QuController.java | 316 +++++++++++ .../backend/model/qu/dto/QuAnswerDTO.java | 42 ++ .../com/guwan/backend/model/qu/dto/QuDTO.java | 53 ++ .../guwan/backend/model/qu/dto/QuRepoDTO.java | 38 ++ .../model/qu/dto/export/QuExportDTO.java | 45 ++ .../model/qu/dto/export/QuImportDTO.java | 23 + .../backend/model/qu/dto/ext/QuDetailDTO.java | 33 ++ .../model/qu/dto/request/QuQueryReqDTO.java | 38 ++ .../qu/dto/request/QuRepoBatchReqDTO.java | 34 ++ .../com/guwan/backend/model/qu/entity/Qu.java | 75 +++ .../backend/model/qu/entity/QuAnswer.java | 58 ++ .../guwan/backend/model/qu/entity/QuRepo.java | 50 ++ .../guwan/backend/model/qu/enums/QuType.java | 26 + .../model/qu/mapper/QuAnswerMapper.java | 16 + .../backend/model/qu/mapper/QuMapper.java | 56 ++ .../backend/model/qu/mapper/QuRepoMapper.java | 16 + .../model/qu/service/QuAnswerService.java | 48 ++ .../model/qu/service/QuRepoService.java | 59 ++ .../backend/model/qu/service/QuService.java | 76 +++ .../qu/service/impl/QuAnswerServiceImpl.java | 144 +++++ .../qu/service/impl/QuRepoServiceImpl.java | 175 ++++++ .../model/qu/service/impl/QuServiceImpl.java | 277 +++++++++ .../model/qu/utils/ImageCheckUtils.java | 31 + .../controller/SysConfigController.java | 70 +++ .../model/sys/config/dto/SysConfigDTO.java | 39 ++ .../model/sys/config/entity/SysConfig.java | 53 ++ .../sys/config/mapper/SysConfigMapper.java | 16 + .../sys/config/service/SysConfigService.java | 22 + .../service/impl/SysConfigServiceImpl.java | 34 ++ .../controller/SysDepartController.java | 150 +++++ .../model/sys/depart/dto/SysDepartDTO.java | 42 ++ .../depart/dto/request/DepartSortReqDTO.java | 28 + .../depart/dto/response/SysDepartTreeDTO.java | 28 + .../model/sys/depart/entity/SysDepart.java | 59 ++ .../sys/depart/mapper/SysDepartMapper.java | 28 + .../sys/depart/service/SysDepartService.java | 62 ++ .../service/impl/SysDepartServiceImpl.java | 288 ++++++++++ .../sys/system/mapper/SysDictMapper.java | 29 + .../sys/system/service/SysDictService.java | 21 + .../service/impl/SysDictServiceImpl.java | 21 + .../user/controller/SysRoleController.java | 77 +++ .../user/controller/SysUserController.java | 177 ++++++ .../model/sys/user/dto/SysRoleDTO.java | 30 + .../model/sys/user/dto/SysUserDTO.java | 55 ++ .../model/sys/user/dto/SysUserRoleDTO.java | 33 ++ .../user/dto/request/SysUserLoginReqDTO.java | 29 + .../user/dto/request/SysUserSaveReqDTO.java | 43 ++ .../user/dto/request/SysUserTokenReqDTO.java | 26 + .../user/dto/response/SysUserLoginDTO.java | 55 ++ .../model/sys/user/entity/SysRole.java | 36 ++ .../model/sys/user/entity/SysUser.java | 83 +++ .../model/sys/user/entity/SysUserRole.java | 42 ++ .../model/sys/user/mapper/SysRoleMapper.java | 15 + .../model/sys/user/mapper/SysUserMapper.java | 16 + .../sys/user/mapper/SysUserRoleMapper.java | 16 + .../sys/user/service/SysRoleService.java | 25 + .../sys/user/service/SysUserRoleService.java | 61 ++ .../sys/user/service/SysUserService.java | 72 +++ .../user/service/impl/SysRoleServiceImpl.java | 42 ++ .../service/impl/SysUserRoleServiceImpl.java | 128 +++++ .../user/service/impl/SysUserServiceImpl.java | 253 +++++++++ .../guwan/backend/model/user/UserUtils.java | 56 ++ .../book/controller/UserBookController.java | 76 +++ .../model/user/book/dto/UserBookDTO.java | 52 ++ .../model/user/book/entity/UserBook.java | 78 +++ .../user/book/mapper/UserBookMapper.java | 16 + .../user/book/service/UserBookService.java | 40 ++ .../service/impl/UserBookServiceImpl.java | 155 +++++ .../exam/controller/UserExamController.java | 65 +++ .../model/user/exam/dto/UserExamDTO.java | 50 ++ .../user/exam/dto/request/UserExamReqDTO.java | 30 + .../exam/dto/response/UserExamRespDTO.java | 29 + .../model/user/exam/entity/UserExam.java | 70 +++ .../user/exam/mapper/UserExamMapper.java | 29 + .../user/exam/service/UserExamService.java | 43 ++ .../service/impl/UserExamServiceImpl.java | 88 +++ .../java/com/guwan/backend/test/Father.java | 15 + .../com/guwan/backend/test/FatherCopy.java | 15 + src/main/java/com/guwan/backend/test/Son.java | 12 + .../java/com/guwan/backend/test/TestCopy.java | 22 + .../com/guwan/backend/util/MinioUtil.java | 19 +- src/main/resources/application.yml | 12 +- .../mapper/exam/ExamDepartMapper.xml | 17 + src/main/resources/mapper/exam/ExamMapper.xml | 55 ++ .../resources/mapper/exam/ExamRepoMapper.xml | 38 ++ 192 files changed, 11545 insertions(+), 34 deletions(-) create mode 100644 deps.txt create mode 100644 logs/backend.log.0 create mode 100644 logs/backend.log.1 create mode 100644 src/main/java/com/guwan/backend/VideoDuration.java create mode 100644 src/main/java/com/guwan/backend/controller/Ac.java create mode 100644 src/main/java/com/guwan/backend/controller/CompileResult.java create mode 100644 src/main/java/com/guwan/backend/controller/DockerCppRunner.java create mode 100644 src/main/java/com/guwan/backend/controller/TestCase.java create mode 100644 src/main/java/com/guwan/backend/core/BeanMapper.java create mode 100644 src/main/java/com/guwan/backend/core/annon/Dict.java create mode 100644 src/main/java/com/guwan/backend/core/api/ApiError.java create mode 100644 src/main/java/com/guwan/backend/core/api/ApiRest.java create mode 100644 src/main/java/com/guwan/backend/core/api/controller/BaseController.java create mode 100644 src/main/java/com/guwan/backend/core/api/dto/BaseDTO.java create mode 100644 src/main/java/com/guwan/backend/core/api/dto/BaseIdReqDTO.java create mode 100644 src/main/java/com/guwan/backend/core/api/dto/BaseIdRespDTO.java create mode 100644 src/main/java/com/guwan/backend/core/api/dto/BaseIdsReqDTO.java create mode 100644 src/main/java/com/guwan/backend/core/api/dto/BaseStateReqDTO.java create mode 100644 src/main/java/com/guwan/backend/core/api/dto/PagingReqDTO.java create mode 100644 src/main/java/com/guwan/backend/core/api/dto/PagingRespDTO.java create mode 100644 src/main/java/com/guwan/backend/core/api/utils/JsonConverter.java create mode 100644 src/main/java/com/guwan/backend/core/enums/CommonState.java create mode 100644 src/main/java/com/guwan/backend/core/enums/OpenType.java create mode 100644 src/main/java/com/guwan/backend/core/exception/ServiceException.java create mode 100644 src/main/java/com/guwan/backend/core/exception/ServiceExceptionHandler.java create mode 100644 src/main/java/com/guwan/backend/core/utils/CronUtils.java create mode 100644 src/main/java/com/guwan/backend/core/utils/DateUtils.java create mode 100644 src/main/java/com/guwan/backend/core/utils/IpUtils.java create mode 100644 src/main/java/com/guwan/backend/core/utils/Reflections.java create mode 100644 src/main/java/com/guwan/backend/core/utils/SpringUtils.java create mode 100644 src/main/java/com/guwan/backend/core/utils/StringUtils.java create mode 100644 src/main/java/com/guwan/backend/core/utils/excel/ExportExcel.java create mode 100644 src/main/java/com/guwan/backend/core/utils/excel/ImportExcel.java create mode 100644 src/main/java/com/guwan/backend/core/utils/excel/annotation/ExcelField.java create mode 100644 src/main/java/com/guwan/backend/core/utils/excel/fieldtype/ListType.java create mode 100644 src/main/java/com/guwan/backend/core/utils/file/Md5Util.java create mode 100644 src/main/java/com/guwan/backend/core/utils/passwd/PassHandler.java create mode 100644 src/main/java/com/guwan/backend/core/utils/passwd/PassInfo.java create mode 100644 src/main/java/com/guwan/backend/model/exam/controller/ExamController.java create mode 100644 src/main/java/com/guwan/backend/model/exam/dto/ExamDTO.java create mode 100644 src/main/java/com/guwan/backend/model/exam/dto/ExamDepartDTO.java create mode 100644 src/main/java/com/guwan/backend/model/exam/dto/ExamRepoDTO.java create mode 100644 src/main/java/com/guwan/backend/model/exam/dto/ext/ExamRepoExtDTO.java create mode 100644 src/main/java/com/guwan/backend/model/exam/dto/request/ExamSaveReqDTO.java create mode 100644 src/main/java/com/guwan/backend/model/exam/dto/response/ExamOnlineRespDTO.java create mode 100644 src/main/java/com/guwan/backend/model/exam/dto/response/ExamReviewRespDTO.java create mode 100644 src/main/java/com/guwan/backend/model/exam/entity/Exam.java create mode 100644 src/main/java/com/guwan/backend/model/exam/entity/ExamDepart.java create mode 100644 src/main/java/com/guwan/backend/model/exam/entity/ExamRepo.java create mode 100644 src/main/java/com/guwan/backend/model/exam/enums/ExamState.java create mode 100644 src/main/java/com/guwan/backend/model/exam/mapper/ExamDepartMapper.java create mode 100644 src/main/java/com/guwan/backend/model/exam/mapper/ExamMapper.java create mode 100644 src/main/java/com/guwan/backend/model/exam/mapper/ExamRepoMapper.java create mode 100644 src/main/java/com/guwan/backend/model/exam/service/ExamDepartService.java create mode 100644 src/main/java/com/guwan/backend/model/exam/service/ExamRepoService.java create mode 100644 src/main/java/com/guwan/backend/model/exam/service/ExamService.java create mode 100644 src/main/java/com/guwan/backend/model/exam/service/impl/ExamDepartServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/model/exam/service/impl/ExamRepoServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/model/exam/service/impl/ExamServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/model/paper/controller/PaperController.java create mode 100644 src/main/java/com/guwan/backend/model/paper/dto/PaperDTO.java create mode 100644 src/main/java/com/guwan/backend/model/paper/dto/PaperQuAnswerDTO.java create mode 100644 src/main/java/com/guwan/backend/model/paper/dto/PaperQuDTO.java create mode 100644 src/main/java/com/guwan/backend/model/paper/dto/ext/PaperQuAnswerExtDTO.java create mode 100644 src/main/java/com/guwan/backend/model/paper/dto/ext/PaperQuDetailDTO.java create mode 100644 src/main/java/com/guwan/backend/model/paper/dto/request/PaperAnswerDTO.java create mode 100644 src/main/java/com/guwan/backend/model/paper/dto/request/PaperCreateReqDTO.java create mode 100644 src/main/java/com/guwan/backend/model/paper/dto/request/PaperListReqDTO.java create mode 100644 src/main/java/com/guwan/backend/model/paper/dto/request/PaperQuQueryDTO.java create mode 100644 src/main/java/com/guwan/backend/model/paper/dto/response/ExamDetailRespDTO.java create mode 100644 src/main/java/com/guwan/backend/model/paper/dto/response/ExamResultRespDTO.java create mode 100644 src/main/java/com/guwan/backend/model/paper/dto/response/PaperListRespDTO.java create mode 100644 src/main/java/com/guwan/backend/model/paper/entity/Paper.java create mode 100644 src/main/java/com/guwan/backend/model/paper/entity/PaperQu.java create mode 100644 src/main/java/com/guwan/backend/model/paper/entity/PaperQuAnswer.java create mode 100644 src/main/java/com/guwan/backend/model/paper/enums/ExamState.java create mode 100644 src/main/java/com/guwan/backend/model/paper/enums/PaperState.java create mode 100644 src/main/java/com/guwan/backend/model/paper/job/BreakExamJob.java create mode 100644 src/main/java/com/guwan/backend/model/paper/mapper/PaperMapper.java create mode 100644 src/main/java/com/guwan/backend/model/paper/mapper/PaperQuAnswerMapper.java create mode 100644 src/main/java/com/guwan/backend/model/paper/mapper/PaperQuMapper.java create mode 100644 src/main/java/com/guwan/backend/model/paper/service/PaperQuAnswerService.java create mode 100644 src/main/java/com/guwan/backend/model/paper/service/PaperQuService.java create mode 100644 src/main/java/com/guwan/backend/model/paper/service/PaperService.java create mode 100644 src/main/java/com/guwan/backend/model/paper/service/impl/PaperQuAnswerServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/model/paper/service/impl/PaperQuServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/model/paper/service/impl/PaperServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/model/qu/controller/QuController.java create mode 100644 src/main/java/com/guwan/backend/model/qu/dto/QuAnswerDTO.java create mode 100644 src/main/java/com/guwan/backend/model/qu/dto/QuDTO.java create mode 100644 src/main/java/com/guwan/backend/model/qu/dto/QuRepoDTO.java create mode 100644 src/main/java/com/guwan/backend/model/qu/dto/export/QuExportDTO.java create mode 100644 src/main/java/com/guwan/backend/model/qu/dto/export/QuImportDTO.java create mode 100644 src/main/java/com/guwan/backend/model/qu/dto/ext/QuDetailDTO.java create mode 100644 src/main/java/com/guwan/backend/model/qu/dto/request/QuQueryReqDTO.java create mode 100644 src/main/java/com/guwan/backend/model/qu/dto/request/QuRepoBatchReqDTO.java create mode 100644 src/main/java/com/guwan/backend/model/qu/entity/Qu.java create mode 100644 src/main/java/com/guwan/backend/model/qu/entity/QuAnswer.java create mode 100644 src/main/java/com/guwan/backend/model/qu/entity/QuRepo.java create mode 100644 src/main/java/com/guwan/backend/model/qu/enums/QuType.java create mode 100644 src/main/java/com/guwan/backend/model/qu/mapper/QuAnswerMapper.java create mode 100644 src/main/java/com/guwan/backend/model/qu/mapper/QuMapper.java create mode 100644 src/main/java/com/guwan/backend/model/qu/mapper/QuRepoMapper.java create mode 100644 src/main/java/com/guwan/backend/model/qu/service/QuAnswerService.java create mode 100644 src/main/java/com/guwan/backend/model/qu/service/QuRepoService.java create mode 100644 src/main/java/com/guwan/backend/model/qu/service/QuService.java create mode 100644 src/main/java/com/guwan/backend/model/qu/service/impl/QuAnswerServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/model/qu/service/impl/QuRepoServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/model/qu/service/impl/QuServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/model/qu/utils/ImageCheckUtils.java create mode 100644 src/main/java/com/guwan/backend/model/sys/config/controller/SysConfigController.java create mode 100644 src/main/java/com/guwan/backend/model/sys/config/dto/SysConfigDTO.java create mode 100644 src/main/java/com/guwan/backend/model/sys/config/entity/SysConfig.java create mode 100644 src/main/java/com/guwan/backend/model/sys/config/mapper/SysConfigMapper.java create mode 100644 src/main/java/com/guwan/backend/model/sys/config/service/SysConfigService.java create mode 100644 src/main/java/com/guwan/backend/model/sys/config/service/impl/SysConfigServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/model/sys/depart/controller/SysDepartController.java create mode 100644 src/main/java/com/guwan/backend/model/sys/depart/dto/SysDepartDTO.java create mode 100644 src/main/java/com/guwan/backend/model/sys/depart/dto/request/DepartSortReqDTO.java create mode 100644 src/main/java/com/guwan/backend/model/sys/depart/dto/response/SysDepartTreeDTO.java create mode 100644 src/main/java/com/guwan/backend/model/sys/depart/entity/SysDepart.java create mode 100644 src/main/java/com/guwan/backend/model/sys/depart/mapper/SysDepartMapper.java create mode 100644 src/main/java/com/guwan/backend/model/sys/depart/service/SysDepartService.java create mode 100644 src/main/java/com/guwan/backend/model/sys/depart/service/impl/SysDepartServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/model/sys/system/mapper/SysDictMapper.java create mode 100644 src/main/java/com/guwan/backend/model/sys/system/service/SysDictService.java create mode 100644 src/main/java/com/guwan/backend/model/sys/system/service/impl/SysDictServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/controller/SysRoleController.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/controller/SysUserController.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/dto/SysRoleDTO.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/dto/SysUserDTO.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/dto/SysUserRoleDTO.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/dto/request/SysUserLoginReqDTO.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/dto/request/SysUserSaveReqDTO.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/dto/request/SysUserTokenReqDTO.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/dto/response/SysUserLoginDTO.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/entity/SysRole.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/entity/SysUser.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/entity/SysUserRole.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/mapper/SysRoleMapper.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/mapper/SysUserMapper.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/mapper/SysUserRoleMapper.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/service/SysRoleService.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/service/SysUserRoleService.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/service/SysUserService.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/service/impl/SysRoleServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/service/impl/SysUserRoleServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/model/sys/user/service/impl/SysUserServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/model/user/UserUtils.java create mode 100644 src/main/java/com/guwan/backend/model/user/book/controller/UserBookController.java create mode 100644 src/main/java/com/guwan/backend/model/user/book/dto/UserBookDTO.java create mode 100644 src/main/java/com/guwan/backend/model/user/book/entity/UserBook.java create mode 100644 src/main/java/com/guwan/backend/model/user/book/mapper/UserBookMapper.java create mode 100644 src/main/java/com/guwan/backend/model/user/book/service/UserBookService.java create mode 100644 src/main/java/com/guwan/backend/model/user/book/service/impl/UserBookServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/model/user/exam/controller/UserExamController.java create mode 100644 src/main/java/com/guwan/backend/model/user/exam/dto/UserExamDTO.java create mode 100644 src/main/java/com/guwan/backend/model/user/exam/dto/request/UserExamReqDTO.java create mode 100644 src/main/java/com/guwan/backend/model/user/exam/dto/response/UserExamRespDTO.java create mode 100644 src/main/java/com/guwan/backend/model/user/exam/entity/UserExam.java create mode 100644 src/main/java/com/guwan/backend/model/user/exam/mapper/UserExamMapper.java create mode 100644 src/main/java/com/guwan/backend/model/user/exam/service/UserExamService.java create mode 100644 src/main/java/com/guwan/backend/model/user/exam/service/impl/UserExamServiceImpl.java create mode 100644 src/main/java/com/guwan/backend/test/Father.java create mode 100644 src/main/java/com/guwan/backend/test/FatherCopy.java create mode 100644 src/main/java/com/guwan/backend/test/Son.java create mode 100644 src/main/java/com/guwan/backend/test/TestCopy.java create mode 100644 src/main/resources/mapper/exam/ExamDepartMapper.xml create mode 100644 src/main/resources/mapper/exam/ExamMapper.xml create mode 100644 src/main/resources/mapper/exam/ExamRepoMapper.xml diff --git a/deps.txt b/deps.txt new file mode 100644 index 0000000..98cb489 --- /dev/null +++ b/deps.txt @@ -0,0 +1,455 @@ +[INFO] Scanning for projects... +[WARNING] +[WARNING] Some problems were encountered while building the effective model for com.guwan:backend:jar:0.0.1-SNAPSHOT +[WARNING] 'dependencies.dependency.(groupId:artifactId:type:classifier)' must be unique: com.aliyun:dysmsapi20170525:jar -> version 2.0.24 vs 3.0.0 @ line 139, column 21 +[WARNING] 'dependencies.dependency.(groupId:artifactId:type:classifier)' must be unique: commons-io:commons-io:jar -> version 2.11.0 vs 2.18.0 @ line 436, column 21 +[WARNING] +[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build. +[WARNING] +[WARNING] For this reason, future Maven versions might no longer support building such malformed projects. +[WARNING] +[INFO] +[INFO] -------------------------< com.guwan:backend >-------------------------- +[INFO] Building backend 0.0.1-SNAPSHOT +[INFO] --------------------------------[ jar ]--------------------------------- +[WARNING] The POM for com.arcsoft.face:arcsoft-sdk-face:jar:4.1.1.0 is missing, no dependency information available +[INFO] +[INFO] --- maven-dependency-plugin:3.6.1:tree (default-cli) @ backend --- +[INFO] com.guwan:backend:jar:0.0.1-SNAPSHOT +[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:3.2.1:compile +[INFO] | +- org.springframework.boot:spring-boot-starter:jar:3.2.1:compile +[INFO] | | +- org.springframework.boot:spring-boot:jar:3.2.1:compile +[INFO] | | \- jakarta.annotation:jakarta.annotation-api:jar:2.1.1:compile +[INFO] | +- org.springframework.boot:spring-boot-starter-json:jar:3.2.1:compile +[INFO] | | +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.15.3:compile +[INFO] | | \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.15.3:compile +[INFO] | +- org.springframework.boot:spring-boot-starter-tomcat:jar:3.2.1:compile +[INFO] | | +- org.apache.tomcat.embed:tomcat-embed-core:jar:10.1.17:compile +[INFO] | | \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:10.1.17:compile +[INFO] | +- org.springframework:spring-web:jar:6.1.2:compile +[INFO] | | \- org.springframework:spring-beans:jar:6.1.2:compile +[INFO] | \- org.springframework:spring-webmvc:jar:6.1.2:compile +[INFO] | \- org.springframework:spring-expression:jar:6.1.2:compile +[INFO] +- com.mysql:mysql-connector-j:jar:8.1.0:runtime +[INFO] +- org.projectlombok:lombok:jar:1.18.30:compile +[INFO] +- org.springframework.boot:spring-boot-starter-test:jar:3.2.1:test +[INFO] | +- org.springframework.boot:spring-boot-test:jar:3.2.1:test +[INFO] | +- org.springframework.boot:spring-boot-test-autoconfigure:jar:3.2.1:test +[INFO] | +- com.jayway.jsonpath:json-path:jar:2.8.0:test +[INFO] | +- jakarta.xml.bind:jakarta.xml.bind-api:jar:4.0.1:compile +[INFO] | | \- jakarta.activation:jakarta.activation-api:jar:2.1.2:compile +[INFO] | +- net.minidev:json-smart:jar:2.5.0:test +[INFO] | | \- net.minidev:accessors-smart:jar:2.5.0:test +[INFO] | | \- org.ow2.asm:asm:jar:9.3:test +[INFO] | +- org.assertj:assertj-core:jar:3.24.2:test +[INFO] | | \- net.bytebuddy:byte-buddy:jar:1.14.10:test +[INFO] | +- org.awaitility:awaitility:jar:4.2.0:test +[INFO] | +- org.hamcrest:hamcrest:jar:2.2:test +[INFO] | +- org.junit.jupiter:junit-jupiter:jar:5.10.1:test +[INFO] | | +- org.junit.jupiter:junit-jupiter-api:jar:5.10.1:test +[INFO] | | | +- org.opentest4j:opentest4j:jar:1.3.0:test +[INFO] | | | +- org.junit.platform:junit-platform-commons:jar:1.10.1:test +[INFO] | | | \- org.apiguardian:apiguardian-api:jar:1.1.2:test +[INFO] | | +- org.junit.jupiter:junit-jupiter-params:jar:5.10.1:test +[INFO] | | \- org.junit.jupiter:junit-jupiter-engine:jar:5.10.1:test +[INFO] | | \- org.junit.platform:junit-platform-engine:jar:1.10.1:test +[INFO] | +- org.mockito:mockito-core:jar:5.7.0:test +[INFO] | | +- net.bytebuddy:byte-buddy-agent:jar:1.14.10:test +[INFO] | | \- org.objenesis:objenesis:jar:3.3:test +[INFO] | +- org.mockito:mockito-junit-jupiter:jar:5.7.0:test +[INFO] | +- org.skyscreamer:jsonassert:jar:1.5.1:test +[INFO] | | \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test +[INFO] | +- org.springframework:spring-core:jar:6.1.2:compile +[INFO] | | \- org.springframework:spring-jcl:jar:6.1.2:compile +[INFO] | +- org.springframework:spring-test:jar:6.1.2:test +[INFO] | \- org.xmlunit:xmlunit-core:jar:2.9.1:test +[INFO] +- com.baomidou:mybatis-plus-boot-starter:jar:3.5.5:compile +[INFO] | +- com.baomidou:mybatis-plus:jar:3.5.5:compile +[INFO] | | +- com.baomidou:mybatis-plus-core:jar:3.5.5:compile +[INFO] | | +- com.baomidou:mybatis-plus-annotation:jar:3.5.5:compile +[INFO] | | +- com.baomidou:mybatis-plus-extension:jar:3.5.5:compile +[INFO] | | +- org.mybatis:mybatis:jar:3.5.15:compile +[INFO] | | \- com.github.jsqlparser:jsqlparser:jar:4.6:compile +[INFO] | +- com.baomidou:mybatis-plus-spring-boot-autoconfigure:jar:3.5.5:compile +[INFO] | +- org.springframework.boot:spring-boot-autoconfigure:jar:3.2.1:compile +[INFO] | \- org.springframework.boot:spring-boot-starter-jdbc:jar:3.2.1:compile +[INFO] | +- com.zaxxer:HikariCP:jar:5.0.1:compile +[INFO] | \- org.springframework:spring-jdbc:jar:6.1.2:compile +[INFO] +- org.mybatis:mybatis-spring:jar:3.0.3:compile +[INFO] +- org.springframework.boot:spring-boot-starter-data-redis:jar:3.2.1:compile +[INFO] | +- io.lettuce:lettuce-core:jar:6.3.0.RELEASE:compile +[INFO] | | \- io.projectreactor:reactor-core:jar:3.6.1:compile +[INFO] | | \- org.reactivestreams:reactive-streams:jar:1.0.4:compile +[INFO] | \- org.springframework.data:spring-data-redis:jar:3.2.1:compile +[INFO] | +- org.springframework.data:spring-data-keyvalue:jar:3.2.1:compile +[INFO] | \- org.springframework:spring-oxm:jar:6.1.2:compile +[INFO] +- org.apache.commons:commons-pool2:jar:2.12.0:compile +[INFO] +- org.springframework.boot:spring-boot-starter-validation:jar:3.2.1:compile +[INFO] | +- org.apache.tomcat.embed:tomcat-embed-el:jar:10.1.17:compile +[INFO] | \- org.hibernate.validator:hibernate-validator:jar:8.0.1.Final:compile +[INFO] | +- jakarta.validation:jakarta.validation-api:jar:3.0.2:compile +[INFO] | +- org.jboss.logging:jboss-logging:jar:3.5.3.Final:compile +[INFO] | \- com.fasterxml:classmate:jar:1.6.0:compile +[INFO] +- com.fasterxml.jackson.core:jackson-databind:jar:2.15.3:compile +[INFO] | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.15.3:compile +[INFO] | \- com.fasterxml.jackson.core:jackson-core:jar:2.15.3:compile +[INFO] +- org.springframework.boot:spring-boot-starter-security:jar:3.2.1:compile +[INFO] | +- org.springframework:spring-aop:jar:6.1.2:compile +[INFO] | +- org.springframework.security:spring-security-config:jar:6.2.1:compile +[INFO] | | \- org.springframework.security:spring-security-core:jar:6.2.1:compile +[INFO] | \- org.springframework.security:spring-security-web:jar:6.2.1:compile +[INFO] +- io.jsonwebtoken:jjwt-api:jar:0.11.5:compile +[INFO] +- io.jsonwebtoken:jjwt-impl:jar:0.11.5:runtime +[INFO] +- io.jsonwebtoken:jjwt-jackson:jar:0.11.5:runtime +[INFO] +- com.aliyun:dysmsapi20170525:jar:3.0.0:compile +[INFO] | +- com.aliyun:tea-util:jar:0.2.22:compile +[INFO] | +- com.aliyun:endpoint-util:jar:0.0.7:compile +[INFO] | +- com.aliyun:tea:jar:1.2.7:compile +[INFO] | | \- org.jacoco:org.jacoco.agent:jar:runtime:0.8.4:compile +[INFO] | +- com.aliyun:tea-openapi:jar:0.3.4:compile +[INFO] | | +- com.aliyun:credentials-java:jar:0.3.3:compile +[INFO] | | | +- org.ini4j:ini4j:jar:0.5.4:compile +[INFO] | | | +- com.sun.xml.bind:jaxb-core:jar:4.0.4:compile +[INFO] | | | \- com.sun.xml.bind:jaxb-impl:jar:4.0.4:compile +[INFO] | | +- com.aliyun:alibabacloud-gateway-spi:jar:0.0.1:compile +[INFO] | | \- com.aliyun:tea-xml:jar:0.1.6:compile +[INFO] | | \- org.dom4j:dom4j:jar:2.0.3:compile +[INFO] | \- com.aliyun:openapiutil:jar:0.2.1:compile +[INFO] | \- org.bouncycastle:bcpkix-jdk15on:jar:1.70:compile +[INFO] | +- org.bouncycastle:bcprov-jdk15on:jar:1.70:compile +[INFO] | \- org.bouncycastle:bcutil-jdk15on:jar:1.70:compile +[INFO] +- org.springframework.boot:spring-boot-starter-mail:jar:3.2.1:compile +[INFO] | +- org.springframework:spring-context-support:jar:6.1.2:compile +[INFO] | \- org.eclipse.angus:jakarta.mail:jar:2.0.2:compile +[INFO] | \- org.eclipse.angus:angus-activation:jar:2.0.1:runtime +[INFO] +- org.springframework.boot:spring-boot-starter-thymeleaf:jar:3.2.1:compile +[INFO] | \- org.thymeleaf:thymeleaf-spring6:jar:3.1.2.RELEASE:compile +[INFO] | \- org.thymeleaf:thymeleaf:jar:3.1.2.RELEASE:compile +[INFO] | +- org.attoparser:attoparser:jar:2.0.7.RELEASE:compile +[INFO] | \- org.unbescape:unbescape:jar:1.1.6.RELEASE:compile +[INFO] +- org.apache.commons:commons-lang3:jar:3.13.0:compile +[INFO] +- cn.hutool:hutool-all:jar:5.8.18:compile +[INFO] +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.15.3:compile +[INFO] +- com.alibaba:fastjson:jar:2.0.53:compile +[INFO] | \- com.alibaba.fastjson2:fastjson2-extension:jar:2.0.53:compile +[INFO] | \- com.alibaba.fastjson2:fastjson2:jar:2.0.53:compile +[INFO] +- org.springframework.boot:spring-boot-starter-aop:jar:3.2.1:compile +[INFO] +- org.aspectj:aspectjweaver:jar:1.9.21:compile +[INFO] +- io.minio:minio:jar:8.5.7:compile +[INFO] | +- com.carrotsearch.thirdparty:simple-xml-safe:jar:2.7.1:compile +[INFO] | +- com.google.guava:guava:jar:32.1.3-jre:compile +[INFO] | | +- com.google.guava:failureaccess:jar:1.0.1:compile +[INFO] | | +- com.google.guava:listenablefuture:jar:9999.0-empty-to-avoid-conflict-with-guava:compile +[INFO] | | \- com.google.j2objc:j2objc-annotations:jar:2.8:compile +[INFO] | +- org.bouncycastle:bcprov-jdk18on:jar:1.76:compile +[INFO] | +- org.apache.commons:commons-compress:jar:1.24.0:compile +[INFO] | \- org.xerial.snappy:snappy-java:jar:1.1.10.5:compile +[INFO] +- commons-io:commons-io:jar:2.18.0:compile +[INFO] +- ai.djl:api:jar:0.25.0:compile +[INFO] | +- com.google.code.gson:gson:jar:2.10.1:compile +[INFO] | +- net.java.dev.jna:jna:jar:5.13.0:compile +[INFO] | \- org.slf4j:slf4j-api:jar:2.0.9:compile +[INFO] +- ai.djl.pytorch:pytorch-engine:jar:0.25.0:compile +[INFO] +- ai.djl.pytorch:pytorch-model-zoo:jar:0.25.0:compile +[INFO] +- org.apache.hadoop:hadoop-client:jar:3.3.6:compile +[INFO] | +- org.apache.hadoop:hadoop-common:jar:3.3.6:compile +[INFO] | | +- org.apache.hadoop.thirdparty:hadoop-shaded-protobuf_3_7:jar:1.1.1:compile +[INFO] | | +- commons-net:commons-net:jar:3.9.0:compile +[INFO] | | +- commons-collections:commons-collections:jar:3.2.2:compile +[INFO] | | +- org.eclipse.jetty:jetty-servlet:jar:9.4.51.v20230217:compile +[INFO] | | | \- org.eclipse.jetty:jetty-security:jar:12.0.5:compile +[INFO] | | +- org.eclipse.jetty:jetty-webapp:jar:9.4.51.v20230217:compile +[INFO] | | | \- org.eclipse.jetty:jetty-xml:jar:12.0.5:compile +[INFO] | | +- javax.servlet.jsp:jsp-api:jar:2.1:runtime +[INFO] | | +- com.sun.jersey:jersey-servlet:jar:1.19.4:compile +[INFO] | | +- org.apache.commons:commons-configuration2:jar:2.8.0:compile +[INFO] | | +- org.apache.commons:commons-text:jar:1.10.0:compile +[INFO] | | +- org.apache.avro:avro:jar:1.7.7:compile +[INFO] | | | +- org.codehaus.jackson:jackson-core-asl:jar:1.9.13:compile +[INFO] | | | +- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.13:compile +[INFO] | | | \- com.thoughtworks.paranamer:paranamer:jar:2.3:compile +[INFO] | | +- com.google.re2j:re2j:jar:1.1:compile +[INFO] | | +- org.apache.hadoop:hadoop-auth:jar:3.3.6:compile +[INFO] | | | +- com.nimbusds:nimbus-jose-jwt:jar:9.8.1:compile +[INFO] | | | | \- com.github.stephenc.jcip:jcip-annotations:jar:1.0-1:compile +[INFO] | | | +- org.apache.curator:curator-framework:jar:5.2.0:compile +[INFO] | | | \- org.apache.kerby:kerb-simplekdc:jar:1.0.1:compile +[INFO] | | | +- org.apache.kerby:kerb-client:jar:1.0.1:compile +[INFO] | | | | +- org.apache.kerby:kerby-config:jar:1.0.1:compile +[INFO] | | | | +- org.apache.kerby:kerb-common:jar:1.0.1:compile +[INFO] | | | | | \- org.apache.kerby:kerb-crypto:jar:1.0.1:compile +[INFO] | | | | +- org.apache.kerby:kerb-util:jar:1.0.1:compile +[INFO] | | | | \- org.apache.kerby:token-provider:jar:1.0.1:compile +[INFO] | | | \- org.apache.kerby:kerb-admin:jar:1.0.1:compile +[INFO] | | | +- org.apache.kerby:kerb-server:jar:1.0.1:compile +[INFO] | | | | \- org.apache.kerby:kerb-identity:jar:1.0.1:compile +[INFO] | | | \- org.apache.kerby:kerby-xdr:jar:1.0.1:compile +[INFO] | | +- org.apache.curator:curator-client:jar:5.2.0:compile +[INFO] | | +- org.apache.curator:curator-recipes:jar:5.2.0:compile +[INFO] | | +- io.dropwizard.metrics:metrics-core:jar:4.2.23:compile +[INFO] | | +- org.apache.kerby:kerb-core:jar:1.0.1:compile +[INFO] | | | \- org.apache.kerby:kerby-pkix:jar:1.0.1:compile +[INFO] | | | +- org.apache.kerby:kerby-asn1:jar:1.0.1:compile +[INFO] | | | \- org.apache.kerby:kerby-util:jar:1.0.1:compile +[INFO] | | +- org.codehaus.woodstox:stax2-api:jar:4.2.1:compile +[INFO] | | +- com.fasterxml.woodstox:woodstox-core:jar:5.4.0:compile +[INFO] | | \- dnsjava:dnsjava:jar:2.1.7:compile +[INFO] | +- org.apache.hadoop:hadoop-hdfs-client:jar:3.3.6:compile +[INFO] | +- org.apache.hadoop:hadoop-yarn-api:jar:3.3.6:compile +[INFO] | | \- javax.xml.bind:jaxb-api:jar:2.2.11:compile +[INFO] | +- org.apache.hadoop:hadoop-yarn-client:jar:3.3.6:compile +[INFO] | | +- org.eclipse.jetty.websocket:websocket-client:jar:9.4.51.v20230217:compile +[INFO] | | | +- org.eclipse.jetty:jetty-client:jar:12.0.5:compile +[INFO] | | | | \- org.eclipse.jetty:jetty-alpn-client:jar:12.0.5:compile +[INFO] | | | \- org.eclipse.jetty.websocket:websocket-common:jar:9.4.51.v20230217:compile +[INFO] | | | \- org.eclipse.jetty.websocket:websocket-api:jar:9.4.51.v20230217:compile +[INFO] | | \- org.jline:jline:jar:3.9.0:compile +[INFO] | +- org.apache.hadoop:hadoop-mapreduce-client-core:jar:3.3.6:compile +[INFO] | | \- org.apache.hadoop:hadoop-yarn-common:jar:3.3.6:compile +[INFO] | | +- com.sun.jersey:jersey-client:jar:1.19.4:compile +[INFO] | | \- com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.15.3:compile +[INFO] | +- org.apache.hadoop:hadoop-mapreduce-client-jobclient:jar:3.3.6:compile +[INFO] | | \- org.apache.hadoop:hadoop-mapreduce-client-common:jar:3.3.6:compile +[INFO] | \- org.apache.hadoop:hadoop-annotations:jar:3.3.6:compile +[INFO] +- org.apache.hadoop:hadoop-hdfs:jar:3.3.6:compile +[INFO] | +- org.apache.hadoop.thirdparty:hadoop-shaded-guava:jar:1.1.1:compile +[INFO] | +- org.eclipse.jetty:jetty-server:jar:12.0.5:compile +[INFO] | | +- org.eclipse.jetty:jetty-http:jar:12.0.5:compile +[INFO] | | \- org.eclipse.jetty:jetty-io:jar:12.0.5:compile +[INFO] | +- org.eclipse.jetty:jetty-util:jar:12.0.5:compile +[INFO] | +- org.eclipse.jetty:jetty-util-ajax:jar:12.0.5:compile +[INFO] | +- com.sun.jersey:jersey-core:jar:1.19.4:compile +[INFO] | | \- javax.ws.rs:jsr311-api:jar:1.1.1:compile +[INFO] | +- com.sun.jersey:jersey-server:jar:1.19.4:compile +[INFO] | +- commons-cli:commons-cli:jar:1.2:compile +[INFO] | +- commons-codec:commons-codec:jar:1.16.0:compile +[INFO] | +- commons-logging:commons-logging:jar:1.1.3:compile +[INFO] | +- commons-daemon:commons-daemon:jar:1.0.13:compile +[INFO] | +- ch.qos.reload4j:reload4j:jar:1.2.22:compile +[INFO] | +- com.google.protobuf:protobuf-java:jar:2.5.0:compile +[INFO] | +- javax.servlet:javax.servlet-api:jar:3.1.0:compile +[INFO] | +- io.netty:netty:jar:3.10.6.Final:compile +[INFO] | \- org.fusesource.leveldbjni:leveldbjni-all:jar:1.8:compile +[INFO] +- org.springdoc:springdoc-openapi-starter-webmvc-ui:jar:2.3.0:compile +[INFO] | +- org.springdoc:springdoc-openapi-starter-webmvc-api:jar:2.3.0:compile +[INFO] | | \- org.springdoc:springdoc-openapi-starter-common:jar:2.3.0:compile +[INFO] | | \- io.swagger.core.v3:swagger-core-jakarta:jar:2.2.19:compile +[INFO] | | +- io.swagger.core.v3:swagger-annotations-jakarta:jar:2.2.19:compile +[INFO] | | \- io.swagger.core.v3:swagger-models-jakarta:jar:2.2.19:compile +[INFO] | \- org.webjars:swagger-ui:jar:5.10.3:compile +[INFO] +- com.arcsoft.face:arcsoft-sdk-face:jar:4.1.1.0:compile +[INFO] +- org.springframework.boot:spring-boot-starter-websocket:jar:3.2.1:compile +[INFO] | +- org.springframework:spring-messaging:jar:6.1.2:compile +[INFO] | \- org.springframework:spring-websocket:jar:6.1.2:compile +[INFO] +- io.netty:netty-all:jar:4.1.94.Final:compile +[INFO] | +- io.netty:netty-buffer:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-codec:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-codec-dns:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-codec-haproxy:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-codec-http:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-codec-http2:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-codec-memcache:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-codec-mqtt:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-codec-redis:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-codec-smtp:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-codec-socks:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-codec-stomp:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-codec-xml:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-common:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-handler:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-transport-native-unix-common:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-handler-proxy:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-handler-ssl-ocsp:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-resolver:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-resolver-dns:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-transport:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-transport-rxtx:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-transport-sctp:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-transport-udt:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-transport-classes-epoll:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-transport-classes-kqueue:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-resolver-dns-classes-macos:jar:4.1.104.Final:compile +[INFO] | +- io.netty:netty-transport-native-epoll:jar:linux-x86_64:4.1.104.Final:compile +[INFO] | +- io.netty:netty-transport-native-epoll:jar:linux-aarch_64:4.1.104.Final:runtime +[INFO] | +- io.netty:netty-transport-native-kqueue:jar:osx-x86_64:4.1.104.Final:compile +[INFO] | +- io.netty:netty-transport-native-kqueue:jar:osx-aarch_64:4.1.104.Final:runtime +[INFO] | +- io.netty:netty-resolver-dns-native-macos:jar:osx-x86_64:4.1.104.Final:runtime +[INFO] | \- io.netty:netty-resolver-dns-native-macos:jar:osx-aarch_64:4.1.104.Final:runtime +[INFO] +- cn.easy-es:easy-es-boot-starter:jar:1.1.1:compile +[INFO] | \- cn.easy-es:easy-es-core:jar:1.1.1:compile +[INFO] | \- cn.easy-es:easy-es-extension:jar:1.1.1:compile +[INFO] | +- cn.easy-es:easy-es-annotation:jar:1.1.1:compile +[INFO] | \- cn.easy-es:easy-es-common:jar:1.1.1:compile +[INFO] +- org.elasticsearch.client:elasticsearch-rest-high-level-client:jar:7.14.0:compile +[INFO] | +- org.elasticsearch.plugin:mapper-extras-client:jar:7.14.0:compile +[INFO] | +- org.elasticsearch.plugin:parent-join-client:jar:7.14.0:compile +[INFO] | +- org.elasticsearch.plugin:aggs-matrix-stats-client:jar:7.14.0:compile +[INFO] | +- org.elasticsearch.plugin:rank-eval-client:jar:7.14.0:compile +[INFO] | \- org.elasticsearch.plugin:lang-mustache-client:jar:7.14.0:compile +[INFO] | \- com.github.spullara.mustache.java:compiler:jar:0.9.6:compile +[INFO] +- org.elasticsearch:elasticsearch:jar:7.14.0:compile +[INFO] | +- org.elasticsearch:elasticsearch-core:jar:7.14.0:compile +[INFO] | +- org.elasticsearch:elasticsearch-secure-sm:jar:7.14.0:compile +[INFO] | +- org.elasticsearch:elasticsearch-x-content:jar:7.14.0:compile +[INFO] | | +- com.fasterxml.jackson.dataformat:jackson-dataformat-smile:jar:2.15.3:compile +[INFO] | | +- com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:jar:2.15.3:compile +[INFO] | | \- com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:jar:2.15.3:compile +[INFO] | +- org.elasticsearch:elasticsearch-geo:jar:7.14.0:compile +[INFO] | +- org.apache.lucene:lucene-core:jar:8.9.0:compile +[INFO] | +- org.apache.lucene:lucene-analyzers-common:jar:8.9.0:compile +[INFO] | +- org.apache.lucene:lucene-backward-codecs:jar:8.9.0:compile +[INFO] | +- org.apache.lucene:lucene-grouping:jar:8.9.0:compile +[INFO] | +- org.apache.lucene:lucene-highlighter:jar:8.9.0:compile +[INFO] | +- org.apache.lucene:lucene-join:jar:8.9.0:compile +[INFO] | +- org.apache.lucene:lucene-memory:jar:8.9.0:compile +[INFO] | +- org.apache.lucene:lucene-misc:jar:8.9.0:compile +[INFO] | +- org.apache.lucene:lucene-queries:jar:8.9.0:compile +[INFO] | +- org.apache.lucene:lucene-queryparser:jar:8.9.0:compile +[INFO] | +- org.apache.lucene:lucene-sandbox:jar:8.9.0:compile +[INFO] | +- org.apache.lucene:lucene-spatial-extras:jar:8.9.0:compile +[INFO] | +- org.apache.lucene:lucene-spatial3d:jar:8.9.0:compile +[INFO] | +- org.apache.lucene:lucene-suggest:jar:8.9.0:compile +[INFO] | +- org.elasticsearch:elasticsearch-cli:jar:7.14.0:compile +[INFO] | | \- net.sf.jopt-simple:jopt-simple:jar:5.0.2:compile +[INFO] | +- com.carrotsearch:hppc:jar:0.8.1:compile +[INFO] | +- org.lz4:lz4-java:jar:1.8.0:compile +[INFO] | +- joda-time:joda-time:jar:2.10.10:compile +[INFO] | +- com.tdunning:t-digest:jar:3.2:compile +[INFO] | +- org.hdrhistogram:HdrHistogram:jar:2.1.9:compile +[INFO] | +- org.elasticsearch:jna:jar:5.7.0-1:compile +[INFO] | \- org.elasticsearch:elasticsearch-plugin-classloader:jar:7.14.0:runtime +[INFO] +- org.elasticsearch.client:elasticsearch-rest-client:jar:7.14.0:compile +[INFO] | +- org.apache.httpcomponents:httpclient:jar:4.5.10:compile +[INFO] | +- org.apache.httpcomponents:httpcore:jar:4.4.16:compile +[INFO] | +- org.apache.httpcomponents:httpasyncclient:jar:4.1.5:compile +[INFO] | \- org.apache.httpcomponents:httpcore-nio:jar:4.4.16:compile +[INFO] +- com.squareup.okhttp3:okhttp:jar:4.12.0:compile +[INFO] | +- com.squareup.okio:okio:jar:3.6.0:compile +[INFO] | | \- com.squareup.okio:okio-jvm:jar:3.6.0:compile +[INFO] | | \- org.jetbrains.kotlin:kotlin-stdlib-common:jar:1.9.21:compile +[INFO] | \- org.jetbrains.kotlin:kotlin-stdlib-jdk8:jar:1.9.21:compile +[INFO] | +- org.jetbrains.kotlin:kotlin-stdlib:jar:1.9.21:compile +[INFO] | | \- org.jetbrains:annotations:jar:13.0:compile +[INFO] | \- org.jetbrains.kotlin:kotlin-stdlib-jdk7:jar:1.9.21:compile +[INFO] +- com.mongoplus:mongo-plus-boot-starter:jar:2.1.6.1:compile +[INFO] | +- com.mongoplus:mongo-plus-core:jar:2.1.6:compile +[INFO] | | \- com.mongoplus:mongo-plus-annotation:jar:2.1.6:compile +[INFO] | \- org.springframework:spring-tx:jar:6.1.2:compile +[INFO] +- com.mongoplus:mongo-plus-solon-plugin:jar:2.1.6.1:compile +[INFO] +- org.springframework.boot:spring-boot-starter-data-mongodb:jar:3.2.1:compile +[INFO] | +- org.mongodb:mongodb-driver-sync:jar:4.11.1:compile +[INFO] | | +- org.mongodb:bson:jar:4.11.1:compile +[INFO] | | \- org.mongodb:mongodb-driver-core:jar:4.11.1:compile +[INFO] | | \- org.mongodb:bson-record-codec:jar:4.11.1:runtime +[INFO] | \- org.springframework.data:spring-data-mongodb:jar:4.2.1:compile +[INFO] | \- org.springframework.data:spring-data-commons:jar:3.2.1:compile +[INFO] +- org.springframework.kafka:spring-kafka:jar:3.0.9:compile +[INFO] | +- org.springframework:spring-context:jar:6.1.2:compile +[INFO] | +- org.springframework.retry:spring-retry:jar:2.0.5:compile +[INFO] | +- org.apache.kafka:kafka-clients:jar:3.6.1:compile +[INFO] | | \- com.github.luben:zstd-jni:jar:1.5.5-1:runtime +[INFO] | +- io.micrometer:micrometer-observation:jar:1.12.1:compile +[INFO] | | \- io.micrometer:micrometer-commons:jar:1.12.1:compile +[INFO] | \- com.google.code.findbugs:jsr305:jar:3.0.2:compile +[INFO] +- org.codehaus.janino:janino:jar:3.1.11:compile +[INFO] | \- org.codehaus.janino:commons-compiler:jar:3.1.11:compile +[INFO] +- com.github.ben-manes.caffeine:caffeine:jar:3.1.8:compile +[INFO] | +- org.checkerframework:checker-qual:jar:3.37.0:compile +[INFO] | \- com.google.errorprone:error_prone_annotations:jar:2.21.1:compile +[INFO] +- net.logstash.logback:logstash-logback-encoder:jar:6.6:compile +[INFO] +- org.springframework.cloud:spring-cloud-starter-openfeign:jar:4.1.2:compile +[INFO] | +- org.springframework.cloud:spring-cloud-starter:jar:4.1.3:compile +[INFO] | | +- org.springframework.cloud:spring-cloud-context:jar:4.1.3:compile +[INFO] | | \- org.springframework.security:spring-security-rsa:jar:1.1.3:compile +[INFO] | +- org.springframework.cloud:spring-cloud-openfeign-core:jar:4.1.2:compile +[INFO] | | +- io.github.openfeign.form:feign-form-spring:jar:3.8.0:compile +[INFO] | | | \- io.github.openfeign.form:feign-form:jar:3.8.0:compile +[INFO] | | \- commons-fileupload:commons-fileupload:jar:1.5:compile +[INFO] | +- org.springframework.cloud:spring-cloud-commons:jar:4.1.3:compile +[INFO] | | \- org.springframework.security:spring-security-crypto:jar:6.2.1:compile +[INFO] | +- io.github.openfeign:feign-core:jar:13.2.1:compile +[INFO] | \- io.github.openfeign:feign-slf4j:jar:13.2.1:compile +[INFO] +- com.xuxueli:xxl-job-core:jar:2.4.0:compile +[INFO] | \- org.apache.groovy:groovy:jar:4.0.16:compile +[INFO] +- com.github.docker-java:docker-java:jar:3.2.13:compile +[INFO] | +- com.github.docker-java:docker-java-core:jar:3.2.13:compile +[INFO] | | \- com.github.docker-java:docker-java-api:jar:3.2.13:compile +[INFO] | +- com.github.docker-java:docker-java-transport-jersey:jar:3.2.13:compile +[INFO] | | +- com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:jar:2.15.3:compile +[INFO] | | | \- com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:jar:2.15.3:compile +[INFO] | | +- org.glassfish.jersey.connectors:jersey-apache-connector:jar:3.1.5:compile +[INFO] | | | +- org.glassfish.jersey.core:jersey-common:jar:3.1.5:compile +[INFO] | | | | \- org.glassfish.hk2:osgi-resource-locator:jar:1.0.3:compile +[INFO] | | | \- jakarta.ws.rs:jakarta.ws.rs-api:jar:3.1.0:compile +[INFO] | | +- org.glassfish.jersey.core:jersey-client:jar:3.1.5:compile +[INFO] | | | \- jakarta.inject:jakarta.inject-api:jar:2.0.1:compile +[INFO] | | +- org.glassfish.jersey.inject:jersey-hk2:jar:3.1.5:compile +[INFO] | | | \- org.glassfish.hk2:hk2-locator:jar:3.0.5:compile +[INFO] | | | +- org.glassfish.hk2.external:aopalliance-repackaged:jar:3.0.5:compile +[INFO] | | | +- org.glassfish.hk2:hk2-api:jar:3.0.5:compile +[INFO] | | | \- org.glassfish.hk2:hk2-utils:jar:3.0.5:compile +[INFO] | | +- com.kohlschutter.junixsocket:junixsocket-common:jar:2.3.2:compile +[INFO] | | \- com.kohlschutter.junixsocket:junixsocket-native-common:jar:2.3.2:compile +[INFO] | +- com.github.docker-java:docker-java-transport-netty:jar:3.2.13:compile +[INFO] | \- org.slf4j:jcl-over-slf4j:jar:2.0.9:compile +[INFO] +- com.github.docker-java:docker-java-transport-httpclient5:jar:3.2.13:compile +[INFO] | \- com.github.docker-java:docker-java-transport:jar:3.2.13:compile +[INFO] +- org.apache.httpcomponents.client5:httpclient5:jar:5.2:compile +[INFO] | \- org.apache.httpcomponents.core5:httpcore5-h2:jar:5.2.4:compile +[INFO] +- org.apache.httpcomponents.core5:httpcore5:jar:5.2:compile +[INFO] +- org.reflections:reflections:jar:0.10.2:compile +[INFO] | \- org.javassist:javassist:jar:3.28.0-GA:compile +[INFO] +- io.swagger.parser.v3:swagger-parser:jar:2.1.25:compile +[INFO] | +- io.swagger.parser.v3:swagger-parser-v2-converter:jar:2.1.25:compile +[INFO] | | +- io.swagger:swagger-core:jar:1.6.15:compile +[INFO] | | | \- io.swagger:swagger-models:jar:1.6.15:compile +[INFO] | | | \- io.swagger:swagger-annotations:jar:1.6.15:compile +[INFO] | | +- io.swagger:swagger-parser:jar:1.0.73:compile +[INFO] | | | \- io.swagger:swagger-parser-safe-url-resolver:jar:1.0.73:compile +[INFO] | | +- io.swagger:swagger-compat-spec-parser:jar:1.0.73:compile +[INFO] | | | +- com.github.java-json-tools:json-schema-validator:jar:2.2.14:compile +[INFO] | | | | +- com.github.java-json-tools:jackson-coreutils-equivalence:jar:1.0:compile +[INFO] | | | | +- com.github.java-json-tools:json-schema-core:jar:1.2.14:compile +[INFO] | | | | | +- com.github.java-json-tools:uri-template:jar:0.10:compile +[INFO] | | | | | \- org.mozilla:rhino:jar:1.7.7.2:compile +[INFO] | | | | \- com.googlecode.libphonenumber:libphonenumber:jar:8.11.1:compile +[INFO] | | | \- com.github.java-json-tools:json-patch:jar:1.13:compile +[INFO] | | | +- com.github.java-json-tools:msg-simple:jar:1.2:compile +[INFO] | | | | \- com.github.java-json-tools:btf:jar:1.3:compile +[INFO] | | | \- com.github.java-json-tools:jackson-coreutils:jar:2.0:compile +[INFO] | | +- io.swagger.core.v3:swagger-models:jar:2.2.28:compile +[INFO] | | \- io.swagger.parser.v3:swagger-parser-core:jar:2.1.25:compile +[INFO] | +- io.swagger.parser.v3:swagger-parser-v3:jar:2.1.25:compile +[INFO] | | +- io.swagger.core.v3:swagger-core:jar:2.2.28:compile +[INFO] | | | \- io.swagger.core.v3:swagger-annotations:jar:2.2.28:compile +[INFO] | | \- io.swagger.parser.v3:swagger-parser-safe-url-resolver:jar:2.1.25:compile +[INFO] | \- org.yaml:snakeyaml:jar:2.2:compile +[INFO] +- org.apache.poi:poi-ooxml:jar:5.2.3:compile +[INFO] | +- org.apache.poi:poi:jar:5.2.3:compile +[INFO] | | \- com.zaxxer:SparseBitSet:jar:1.2:compile +[INFO] | +- org.apache.poi:poi-ooxml-lite:jar:5.2.3:compile +[INFO] | +- org.apache.xmlbeans:xmlbeans:jar:5.1.1:compile +[INFO] | | \- xml-apis:xml-apis:jar:1.4.01:compile +[INFO] | +- com.github.virtuald:curvesapi:jar:1.07:compile +[INFO] | \- org.apache.commons:commons-collections4:jar:4.4:compile +[INFO] +- org.apache.poi:poi-scratchpad:jar:5.2.3:compile +[INFO] | \- org.apache.commons:commons-math3:jar:3.6.1:compile +[INFO] +- net.sf.dozer:dozer:jar:5.5.1:compile +[INFO] | \- commons-beanutils:commons-beanutils:jar:1.9.1:compile +[INFO] \- dev.langchain4j:langchain4j-community-dashscope-spring-boot-starter:jar:1.0.0-beta2:compile +[INFO] +- dev.langchain4j:langchain4j-community-dashscope:jar:1.0.0-beta2:compile +[INFO] | +- dev.langchain4j:langchain4j-core:jar:1.0.0-beta2:compile +[INFO] | | \- org.jspecify:jspecify:jar:1.0.0:compile +[INFO] | \- com.alibaba:dashscope-sdk-java:jar:2.18.3:compile +[INFO] | +- io.reactivex.rxjava2:rxjava:jar:2.2.21:compile +[INFO] | +- com.squareup.okhttp3:logging-interceptor:jar:4.12.0:compile +[INFO] | +- com.squareup.okhttp3:okhttp-sse:jar:4.12.0:compile +[INFO] | \- com.github.victools:jsonschema-generator:jar:4.31.1:compile +[INFO] \- ch.qos.logback:logback-classic:jar:1.4.14:compile +[INFO] \- ch.qos.logback:logback-core:jar:1.4.14:compile +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 2.098 s +[INFO] Finished at: 2025-03-20T23:57:43+08:00 +[INFO] ------------------------------------------------------------------------ diff --git a/logs/backend.log.0 b/logs/backend.log.0 new file mode 100644 index 0000000..19225db --- /dev/null +++ b/logs/backend.log.0 @@ -0,0 +1,6 @@ +[2025-03-20 23:38:51.250] - 28460 信息 [main] --- org.apache.catalina.core.StandardService: Starting service [Tomcat] +[2025-03-20 23:38:51.258] - 28460 信息 [main] --- org.apache.catalina.core.StandardEngine: Starting Servlet engine: [Apache Tomcat/10.1.17] +[2025-03-20 23:38:51.347] - 28460 信息 [main] --- org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/]: Initializing Spring embedded WebApplicationContext +[2025-03-20 23:38:54.534] - 28460 信息 [main] --- easy-es: ===> manual index mode activated +[2025-03-20 23:38:54.624] - 28460 信息 [main] --- easy-es: ===> manual index mode activated +[2025-03-20 23:39:03.199] - 28460 信息 [main] --- easy-es: ===> manual index mode activated diff --git a/logs/backend.log.1 b/logs/backend.log.1 new file mode 100644 index 0000000..d8f1704 --- /dev/null +++ b/logs/backend.log.1 @@ -0,0 +1,6 @@ +[2025-03-20 23:37:40.090] - 23732 信息 [main] --- org.apache.catalina.core.StandardService: Starting service [Tomcat] +[2025-03-20 23:37:40.098] - 23732 信息 [main] --- org.apache.catalina.core.StandardEngine: Starting Servlet engine: [Apache Tomcat/10.1.17] +[2025-03-20 23:37:40.196] - 23732 信息 [main] --- org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/]: Initializing Spring embedded WebApplicationContext +[2025-03-20 23:37:44.418] - 23732 信息 [main] --- easy-es: ===> manual index mode activated +[2025-03-20 23:37:44.511] - 23732 信息 [main] --- easy-es: ===> manual index mode activated +[2025-03-20 23:37:53.289] - 23732 信息 [main] --- easy-es: ===> manual index mode activated diff --git a/pom.xml b/pom.xml index a4d41a9..c2ab71e 100644 --- a/pom.xml +++ b/pom.xml @@ -29,6 +29,8 @@ 21 3.5.5 + 3.9 + 5.5.1 @@ -200,11 +202,23 @@ org.apache.hadoop hadoop-client 3.3.6 + + + org.slf4j + slf4j-reload4j + + org.apache.hadoop hadoop-hdfs 3.3.6 + + + org.slf4j + slf4j-reload4j + + @@ -264,6 +278,12 @@ org.elasticsearch elasticsearch 7.14.0 + + + org.apache.logging.log4j + log4j-api + + org.elasticsearch.client @@ -383,8 +403,110 @@ + + + org.apache.poi + poi-ooxml + 5.2.3 + + + org.apache.logging.log4j + log4j-api + + + + + org.apache.poi + poi-scratchpad + 5.2.3 + + + org.apache.logging.log4j + log4j-api + + + + + + commons-io + commons-io + 2.18.0 + + + + + + + + + net.sf.dozer + dozer + ${dozer.version} + + + commons-collections + commons-collections + + + org.slf4j + slf4j-api + + + + + + + dev.langchain4j + langchain4j-community-dashscope-spring-boot-starter + 1.0.0-beta2 + + + + + org.apache.tika + tika-core + 3.1.0 + + + + org.apache.tika + tika-parsers-standard-package + 3.1.0 + + + + org.springframework.boot + spring-boot-starter-webflux + + + + + + diff --git a/readme.md b/readme.md index e7c6fae..096f331 100644 --- a/readme.md +++ b/readme.md @@ -1,3 +1,11 @@ 毕设后端
-如果运行 暂时屏蔽face包 \ No newline at end of file +如果运行 暂时屏蔽face包 + + +mvn dependency:tree > deps.txt +
+分析依赖 +这次主要是日志的 +slf4j-reload4 +log4j-api \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/BackendApplication.java b/src/main/java/com/guwan/backend/BackendApplication.java index 212d45c..2e6ae90 100644 --- a/src/main/java/com/guwan/backend/BackendApplication.java +++ b/src/main/java/com/guwan/backend/BackendApplication.java @@ -9,7 +9,7 @@ import org.springframework.cloud.openfeign.EnableFeignClients; @Slf4j @SpringBootApplication -@MapperScan("com.guwan.backend.mapper") +@MapperScan({"com.guwan.backend.mapper", "com.guwan.backend.model.exam.mapper"}) @EnableFeignClients public class BackendApplication { @@ -20,6 +20,7 @@ public class BackendApplication { @PostConstruct public void init() { + System.out.println("SLF4J Implementation: " + org.slf4j.LoggerFactory.getILoggerFactory().getClass().getName()); log.info("大爱仙尊: http://localhost:8084/daxz.html?id=1"); } diff --git a/src/main/java/com/guwan/backend/VideoDuration.java b/src/main/java/com/guwan/backend/VideoDuration.java new file mode 100644 index 0000000..3a3bb25 --- /dev/null +++ b/src/main/java/com/guwan/backend/VideoDuration.java @@ -0,0 +1,28 @@ +package com.guwan.backend; + +import org.apache.tika.metadata.Metadata; +import org.apache.tika.parser.AutoDetectParser; +import org.apache.tika.parser.ParseContext; +import org.apache.tika.parser.Parser; +import org.apache.tika.sax.BodyContentHandler; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.URL; + +public class VideoDuration { + public static void main(String[] args) { + String preSignedUrl = "http://localhost:9000/videos/ffffad37-9804-4765-ae18-3f8dcda9bea8.mp4"; // Minio 预签名 URL + + try (InputStream stream = new URL(preSignedUrl).openStream()) { + Metadata metadata = new Metadata(); + Parser parser = new AutoDetectParser(); + parser.parse(stream, new BodyContentHandler(), metadata, new ParseContext()); + + String duration = metadata.get("duration"); + System.out.println("视频时长(毫秒): " + duration); + } catch (Exception e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/aspect/OperationLogAspect.java b/src/main/java/com/guwan/backend/aspect/OperationLogAspect.java index c04b20d..62407d8 100644 --- a/src/main/java/com/guwan/backend/aspect/OperationLogAspect.java +++ b/src/main/java/com/guwan/backend/aspect/OperationLogAspect.java @@ -76,6 +76,7 @@ public class OperationLogAspect { // 获取当前用户信息 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + //Java 16+ 模式匹配写法 if (authentication != null && authentication.getPrincipal() instanceof CustomUserDetails userDetails) { sysLog.setUserId(userDetails.getUserId()); sysLog.setUsername(userDetails.getUsername()); diff --git a/src/main/java/com/guwan/backend/constant/CacheConstants.java b/src/main/java/com/guwan/backend/constant/CacheConstants.java index b0771db..005f787 100644 --- a/src/main/java/com/guwan/backend/constant/CacheConstants.java +++ b/src/main/java/com/guwan/backend/constant/CacheConstants.java @@ -3,7 +3,7 @@ package com.guwan.backend.constant; import java.util.List; /** - * 安全相关常量配置 + * 本地缓存相关常量配置 */ public class CacheConstants { diff --git a/src/main/java/com/guwan/backend/controller/Ac.java b/src/main/java/com/guwan/backend/controller/Ac.java new file mode 100644 index 0000000..b1be7b6 --- /dev/null +++ b/src/main/java/com/guwan/backend/controller/Ac.java @@ -0,0 +1,15 @@ +package com.guwan.backend.controller; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Ac{ + List ids; + String str; +} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/controller/CommonController.java b/src/main/java/com/guwan/backend/controller/CommonController.java index 58dbbc8..283fda2 100644 --- a/src/main/java/com/guwan/backend/controller/CommonController.java +++ b/src/main/java/com/guwan/backend/controller/CommonController.java @@ -11,15 +11,36 @@ import com.guwan.backend.mongodb.MongodbUserService; import com.guwan.backend.mongodb.User; import com.guwan.backend.pojo.entity.BookContent; import com.guwan.backend.util.MinioUtil; +import dev.langchain4j.community.model.dashscope.QwenChatModel; +import dev.langchain4j.community.model.dashscope.QwenStreamingChatModel; +import dev.langchain4j.model.chat.response.ChatResponse; +import dev.langchain4j.model.chat.response.StreamingChatResponseHandler; +import io.minio.MinioClient; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; +import org.apache.poi.xslf.usermodel.XMLSlideShow; +import org.apache.poi.xslf.usermodel.XSLFSlide; +import org.apache.tika.metadata.Metadata; +import org.apache.tika.parser.AutoDetectParser; +import org.apache.tika.parser.ParseContext; +import org.apache.tika.parser.Parser; +import org.apache.tika.sax.BodyContentHandler; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import reactor.core.publisher.Flux; +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; +import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; @@ -36,6 +57,8 @@ public class CommonController { private final VoiceServiceClient voiceServiceClient; private final SimpleTTSClient simpleTTSClient; + private final MinioClient minioClient; + @@ -44,6 +67,8 @@ public class CommonController { private final MongodbUserService mongodbUserService; private final EveryReadDetailOfMongodbService everyReadDetailOfMongodbService; + private final QwenChatModel qwenChatModel; + private final QwenStreamingChatModel qwenStreamingChatModel; @PostMapping("/uploadFile") public Result uploadFile(String bucketName, MultipartFile file){ @@ -361,4 +386,135 @@ public class CommonController { } + @GetMapping("/testQwen") + public Result testQwen( + @RequestParam(value = "str1", required = false) String message) { + + var response = qwenChatModel.chat(message); + System.out.println("response = " + response); + return Result.success(response); + } + + + @GetMapping(value = "/testQwenStreaming", produces = "text/steam;charset=UTF-8") + public Flux testQwenStreaming( + @RequestParam(value = "message", required = false) String message) { + + Flux flux = Flux.create(fluxSink -> { + qwenStreamingChatModel.chat(message, new StreamingChatResponseHandler() { + //每一次流式响应的文本 + @Override + public void onPartialResponse(String partialResponse) { + fluxSink.next(partialResponse); + } + + //响应结束的文本 + @Override + public void onCompleteResponse(ChatResponse chatResponse) { + fluxSink.complete(); + } + + @Override + public void onError(Throwable throwable) { + fluxSink.error(throwable); + } + }); + + }); + return flux; + + } + + + @GetMapping("/PPTToImageConverter") + public void PPTToImageConverter() throws IOException { + + String pptFile = "D:\\00_桌面\\公司简介.pptx"; // PPT 文件路径 + String outputDir = "output_images"; // 输出目录 + + FileInputStream inputStream = new FileInputStream(pptFile); + XMLSlideShow ppt = new XMLSlideShow(inputStream); + inputStream.close(); + + // 创建输出目录 + File dir = new File(outputDir); + if (!dir.exists()) { + dir.mkdirs(); + } + + // 获取幻灯片 + int slideNumber = 1; + for (XSLFSlide slide : ppt.getSlides()) { + Dimension pgsize = ppt.getPageSize(); + BufferedImage img = new BufferedImage(pgsize.width, pgsize.height, BufferedImage.TYPE_INT_ARGB); + Graphics2D graphics = img.createGraphics(); + + // 设置背景为白色 + graphics.setPaint(Color.WHITE); + graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height)); + + // 渲染幻灯片 + slide.draw(graphics); + + // 输出为图片 + File outputFile = new File(outputDir + "/slide_" + slideNumber + ".png"); + ImageIO.write(img, "png", outputFile); + System.out.println("Saved slide: " + outputFile.getAbsolutePath()); + + slideNumber++; + } + ppt.close(); + } + + + @GetMapping("/videoDuration") + public void VideoDuration() throws IOException { + + String preSignedUrl = "http://localhost:9000/videos/ffffad37-9804-4765-ae18-3f8dcda9bea8.mp4"; // Minio 预签名 URL + + + // minioClient.getObject() + InputStream stream = minioUtil.getFileInputStream("videos", "ffffad37-9804-4765-ae18-3f8dcda9bea8.mp4"); + + + System.out.println("stream = " + stream); + try { + Metadata metadata = new Metadata(); + Parser parser = new AutoDetectParser(); + parser.parse(stream, new BodyContentHandler(), metadata, new ParseContext()); + + String duration = metadata.get("duration"); + System.out.println("视频时长(毫秒): " + duration); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + @PostMapping("/testPostUseParam") + //测试公司写法 + public void testPostUseParam(@RequestParam("ids") List ids, + @RequestParam("str") String str){ + System.out.println("ids = " + ids); + System.out.println("str = " + str); + } + + @PostMapping("/testPostUseBody") + public void testPostUseBody(@RequestBody Ac ac){ + System.out.println("ac = " + ac); + } + + @GetMapping("/testGetParam") + public void testGetParam(@RequestParam("ids") List ids, + @RequestParam("str") String str){ + System.out.println("ids = " + ids); + System.out.println("str = " + str); + } + + + + + } + + diff --git a/src/main/java/com/guwan/backend/controller/CompileResult.java b/src/main/java/com/guwan/backend/controller/CompileResult.java new file mode 100644 index 0000000..ce10087 --- /dev/null +++ b/src/main/java/com/guwan/backend/controller/CompileResult.java @@ -0,0 +1,27 @@ +package com.guwan.backend.controller; + +class CompileResult { + boolean success; + String message; + + // constructor... +} + +class CaseResult { + boolean passed; + String input; + String expected; + String actual; + String message; + + // 成功构造器 + public CaseResult(boolean passed, String input, + String expected, String actual) { + // ... + } + + // 失败构造器 + public CaseResult(boolean passed, String message) { + // ... + } +} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/controller/CoursesController.java b/src/main/java/com/guwan/backend/controller/CoursesController.java index 8cbbd55..9dfb49a 100644 --- a/src/main/java/com/guwan/backend/controller/CoursesController.java +++ b/src/main/java/com/guwan/backend/controller/CoursesController.java @@ -2,6 +2,8 @@ package com.guwan.backend.controller; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.guwan.backend.common.Result; import com.guwan.backend.mongodb.CategoryService; import com.guwan.backend.pojo.Courses; @@ -9,7 +11,7 @@ import com.guwan.backend.pojo.dto.BSCategory; import com.guwan.backend.service.BSCategoryService; import com.guwan.backend.service.CoursesService; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; + import org.springframework.data.domain.PageRequest; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -45,11 +47,18 @@ public class CoursesController { * @param pageRequest 分页对象 * @return 查询结果 */ - @GetMapping - public Result queryByPage() { + @GetMapping("/homePage") + public Result queryByPage(@RequestParam("page") Integer pageNumber, + @RequestParam("size") Integer size) { // return Result.success(this.coursesService.queryByPage(courses, pageRequest)); - return Result.success(this.coursesService.list().stream() + Page page = new Page<>(pageNumber, size); + + LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + + Page resultPage = this.coursesService.page(page, lambdaQueryWrapper); + + return Result.success(resultPage.getRecords().stream() .peek(course -> { course.setCategoryName(categoryService.list() .stream() diff --git a/src/main/java/com/guwan/backend/controller/DemoController.java b/src/main/java/com/guwan/backend/controller/DemoController.java index d5b054b..9a7f7b5 100644 --- a/src/main/java/com/guwan/backend/controller/DemoController.java +++ b/src/main/java/com/guwan/backend/controller/DemoController.java @@ -12,7 +12,6 @@ import com.mongodb.client.gridfs.model.GridFSFile; import io.minio.MinioClient; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.hadoop.thirdparty.protobuf.Api; import org.elasticsearch.search.SearchHit; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; @@ -21,8 +20,6 @@ import org.springframework.web.client.RestTemplate; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; import java.util.List; @Slf4j diff --git a/src/main/java/com/guwan/backend/controller/DockerController.java b/src/main/java/com/guwan/backend/controller/DockerController.java index 5f4ff5b..b38c260 100644 --- a/src/main/java/com/guwan/backend/controller/DockerController.java +++ b/src/main/java/com/guwan/backend/controller/DockerController.java @@ -1,19 +1,26 @@ package com.guwan.backend.controller; import com.github.dockerjava.api.command.CreateContainerCmd; +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.ExecCreateCmdResponse; import com.github.dockerjava.api.model.*; +import com.github.dockerjava.core.DockerClientBuilder; +import com.github.dockerjava.core.command.ExecStartResultCallback; +import com.github.dockerjava.httpclient5.ApacheDockerHttpClient; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.github.dockerjava.api.DockerClient; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; +import java.util.*; +import java.util.concurrent.TimeUnit; @RestController @RequestMapping("/api/common") @@ -96,6 +103,217 @@ public class DockerController { } + private static final String IMAGE_NAME = "gcc:latest"; + private static final int TIMEOUT_SECONDS = 10; + + /* @GetMapping("/testCpp") + public void testCpp() throws IOException { + + System.out.println("dockerClient = " + dockerClient); + + + try { + // 创建容器 + CreateContainerResponse container = dockerClient.createContainerCmd(IMAGE_NAME) + .withTty(true) + .withWorkingDir("/app") + .exec(); + + String containerId = container.getId(); + dockerClient.startContainerCmd(containerId).exec(); + + // 写入代码(使用cat和here-doc避免转义问题) + String cppCode = "#include \n" + + "int main() { std::cout << \"Hello Docker!\\n\"; return 0; }"; + + execCommand(dockerClient, containerId, + "sh -c 'cat > /app/main.cpp < + dockerClient.removeContainerCmd(c.getId()).withForce(true).exec());*//* + //dockerClient.close(); + } + } + + + private static String execCommand(DockerClient dockerClient, String containerId, String command) + throws Exception { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ExecCreateCmdResponse exec = dockerClient.execCreateCmd(containerId) + .withCmd("sh", "-c", command) + .withAttachStdout(true) + .withAttachStderr(true) + .exec(); + + dockerClient.execStartCmd(exec.getId()) + .exec(new ExecStartResultCallback(outputStream, System.err)) + .awaitCompletion(TIMEOUT_SECONDS, TimeUnit.SECONDS); + + return outputStream.toString().trim(); + }*/ + + + @GetMapping("/judge") + public ResponseEntity> judgeCode() { + Map result = new HashMap<>(); + List testCases = new ArrayList<>(); + + // 真实用户提交的C++代码(示例:A+B问题) + String cppCode = + "#include \n" + + "using namespace std;\n" + + "int main() {\n" + + " int a, b;\n" + + " cin >> a >> b;\n" + + " cout << a + b << endl;\n" + + " return 0;\n" + + "}"; + + // 定义测试用例 + testCases.add(new TestCase("1 2", "3")); // 基础测试 + testCases.add(new TestCase("-5 8", "3")); // 负数测试 + testCases.add(new TestCase("1000000 2000000", "3000000")); // 大数测试 + testCases.add(new TestCase("", "")); // 错误输入测试 + testCases.add(new TestCase("3", "")); // 不完整输入测试 + + String containerId = null; + try { + // 创建容器(使用官方GCC镜像) + CreateContainerResponse container = dockerClient.createContainerCmd("gcc:latest") + .withTty(true) + .withWorkingDir("/app") + .withHostConfig(HostConfig.newHostConfig() + .withMemory(100 * 1024 * 1024L) // 限制内存100MB + .withCpuCount(1L)) // 限制1核CPU + .exec(); + + containerId = container.getId(); + dockerClient.startContainerCmd(containerId).exec(); + + // 1. 写入代码文件 + execCommand(containerId, "mkdir -p /app", 10); + execCommand(containerId, + "bash -c 'cat > /app/main.cpp <> caseResults = new ArrayList<>(); + for (int i = 0; i < testCases.size(); i++) { + TestCase testCase = testCases.get(i); + Map caseResult = new HashMap<>(); + caseResult.put("case_id", i + 1); + caseResult.put("input", testCase.input); + caseResult.put("expected", testCase.expectedOutput); + + try { + // 写入输入文件 + execCommand(containerId, + "bash -c 'cat > /app/input.txt <&1", // 捕获标准错误 + 3 // 超时3秒 + ); + + // 标准化输出处理 + actualOutput = actualOutput.trim() + .replaceAll("\r\n", "\n") + .replaceAll("[ \\t]+", " "); + + // 结果对比 + boolean isPassed = actualOutput.equals(testCase.expectedOutput); + caseResult.put("status", isPassed ? "passed" : "failed"); + caseResult.put("actual", actualOutput); + + // 特殊错误类型检测 + if (actualOutput.contains("Timeout")) { + caseResult.put("status", "time_limit_exceeded"); + } else if (actualOutput.contains("runtime error")) { + caseResult.put("status", "runtime_error"); + } else if (actualOutput.isEmpty()) { + caseResult.put("status", "no_output"); + } + + } catch (Exception e) { + caseResult.put("status", "system_error"); + caseResult.put("message", e.getMessage()); + } + + caseResults.add(caseResult); + } + + result.put("status", "completed"); + result.put("cases", caseResults); + result.put("pass_count", caseResults.stream() + .filter(c -> "passed".equals(c.get("status"))) + .count()); + + } catch (Exception e) { + result.put("status", "system_error"); + result.put("message", e.getMessage()); + } finally { + if (containerId != null) { + dockerClient.removeContainerCmd(containerId) + .withForce(true) + .exec(); + } + } + + return ResponseEntity.ok(result); + } + + // 辅助方法:执行容器命令 + private String execCommand(String containerId, String command, int timeoutSeconds) + throws Exception { + + ByteArrayOutputStream output = new ByteArrayOutputStream(); + ExecCreateCmdResponse exec = dockerClient.execCreateCmd(containerId) + .withCmd("bash", "-c", command) + .withAttachStdout(true) + .withAttachStderr(true) + .exec(); + + dockerClient.execStartCmd(exec.getId()) + .exec(new ExecStartResultCallback(output, output)) + .awaitCompletion(timeoutSeconds, TimeUnit.SECONDS); + + return output.toString().trim(); + } + + // 测试用例类 + static class TestCase { + String input; + String expectedOutput; + + public TestCase(String input, String expectedOutput) { + this.input = input; + this.expectedOutput = expectedOutput; + } + } + diff --git a/src/main/java/com/guwan/backend/controller/DockerCppRunner.java b/src/main/java/com/guwan/backend/controller/DockerCppRunner.java new file mode 100644 index 0000000..8a233ee --- /dev/null +++ b/src/main/java/com/guwan/backend/controller/DockerCppRunner.java @@ -0,0 +1,79 @@ +/* +package com.guwan.backend.controller; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.ExecCreateCmdResponse; +import com.github.dockerjava.core.DockerClientBuilder; +import com.github.dockerjava.core.command.ExecStartResultCallback; +import com.github.dockerjava.httpclient5.ApacheDockerHttpClient; + +import java.io.ByteArrayOutputStream; +import java.util.concurrent.TimeUnit; + +public class DockerCppRunner { + + private static final String IMAGE_NAME = "cpp-runner"; + private static final int TIMEOUT_SECONDS = 10; + + private final DockerClient dockerClient; + + public static void main(String[] args) throws Exception { + DockerClient dockerClient = DockerClientBuilder.getInstance() + .withDockerHttpClient( + new ApacheDockerHttpClient.Builder() + .dockerHost(DockerClientBuilder.getDefaultDockerHost()) + .build() + ).build(); + + try { + // 创建容器 + CreateContainerResponse container = dockerClient.createContainerCmd(IMAGE_NAME) + .withTty(true) + .exec(); + + String containerId = container.getId(); + + // 启动容器 + dockerClient.startContainerCmd(containerId).exec(); + + // 写入 C++ 代码到容器内 + String cppCode = "#include \n" + + "int main() { std::cout << \"Hello Docker!\\n\"; return 0; }"; + + // 将代码写入容器中的文件 + dockerClient.execCreateCmd(containerId) + .withCmd("sh", "-c", "echo '" + cppCode + "' > /app/main.cpp") + .exec(); + + // 编译 C++ 代码 + execCommand(dockerClient, containerId, "g++ /app/main.cpp -o /app/main"); + + // 运行编译后的程序 + String output = execCommand(dockerClient, containerId, "/app/main"); + System.out.println("程序输出: " + output); + + } finally { + // 清理容器 + dockerClient.listContainersCmd().withShowAll(true).exec().forEach(c -> + dockerClient.removeContainerCmd(c.getId()).withForce(true).exec()); + dockerClient.close(); + } + } + + private static String execCommand(DockerClient dockerClient, String containerId, String command) + throws Exception { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ExecCreateCmdResponse exec = dockerClient.execCreateCmd(containerId) + .withCmd("sh", "-c", command) + .withAttachStdout(true) + .withAttachStderr(true) + .exec(); + + dockerClient.execStartCmd(exec.getId()) + .exec(new ExecStartResultCallback(outputStream, System.err)) + .awaitCompletion(TIMEOUT_SECONDS, TimeUnit.SECONDS); + + return outputStream.toString().trim(); + } +}*/ diff --git a/src/main/java/com/guwan/backend/controller/TestCase.java b/src/main/java/com/guwan/backend/controller/TestCase.java new file mode 100644 index 0000000..4886d89 --- /dev/null +++ b/src/main/java/com/guwan/backend/controller/TestCase.java @@ -0,0 +1,13 @@ +package com.guwan.backend.controller; + +// 测试用例类 +class TestCase { + String input; // 输入数据 + String expectedOutput; // 预期输出 + int timeoutSeconds = 2;// 超时时间 + + public TestCase(String input, String expectedOutput) { + this.input = input; + this.expectedOutput = expectedOutput; + } +} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/core/BeanMapper.java b/src/main/java/com/guwan/backend/core/BeanMapper.java new file mode 100644 index 0000000..83e9485 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/BeanMapper.java @@ -0,0 +1,59 @@ +package com.guwan.backend.core; + +import org.dozer.DozerBeanMapper; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + + +/** + * 简单封装Dozer, 实现深度转换Bean<->Bean的Mapper.实现: + * + * 1. 持有Mapper的单例. + * 2. 返回值类型转换. + * 3. 批量转换Collection中的所有对象. + * 4. 区分创建新的B对象与将对象A值复制到已存在的B对象两种函数. + * + */ +public class BeanMapper { + + /** + * 持有Dozer单例, 避免重复创建DozerMapper消耗资源. + */ + private static DozerBeanMapper dozerBeanMapper = new DozerBeanMapper(); + + /** + * 基于Dozer转换对象的类型. + */ + public static T map(Object source, Class destinationClass) { + return dozerBeanMapper.map(source, destinationClass); + } + + /** + * 基于Dozer转换Collection中对象的类型. + */ + public static List mapList(Iterable sourceList, Class destinationClass) { + List destinationList = new ArrayList(); + for (Object sourceObject : sourceList) { + T destinationObject = dozerBeanMapper.map(sourceObject, destinationClass); + destinationList.add(destinationObject); + } + return destinationList; + } + + /** + * 基于Dozer将对象A的值拷贝到对象B中. + */ + public static void copy(Object source, Object destinationObject) { + if(source!=null) { + dozerBeanMapper.map(source, destinationObject); + } + } + + public static List mapList(Collection source, Function mapper) { + return source.stream().map(mapper).collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/core/annon/Dict.java b/src/main/java/com/guwan/backend/core/annon/Dict.java new file mode 100644 index 0000000..effaac7 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/annon/Dict.java @@ -0,0 +1,21 @@ +package com.guwan.backend.core.annon; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 数据字典注解 + * @author bool + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Dict { + + String dicCode(); + + String dicText() default ""; + + String dictTable() default ""; +} diff --git a/src/main/java/com/guwan/backend/core/api/ApiError.java b/src/main/java/com/guwan/backend/core/api/ApiError.java new file mode 100644 index 0000000..4ddd831 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/api/ApiError.java @@ -0,0 +1,67 @@ +package com.guwan.backend.core.api; + + +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 全局错误码定义,用于定义接口的响应数据, + * 枚举名称全部使用代码命名,在系统中调用,免去取名难的问题。 + * @author bool + * @date 2019-06-14 21:15 + */ +@NoArgsConstructor +@AllArgsConstructor +public enum ApiError implements Serializable { + + + /** + * 通用错误,接口参数不全 + */ + ERROR_10010001("参数不全或类型错误!"), + ERROR_10010002("您还未登录,请先登录!"), + ERROR_10010003("数据不存在!"), + ERROR_10010012("图形验证码错误!"), + ERROR_10010013("短信验证码错误!"), + ERROR_10010014("不允许重复评论!"), + + /** + * 考试相关错误 + */ + ERROR_20010001("试题被删除,无法继续考试!"), + ERROR_20010002("您有正在进行的考试!"), + + + ERROR_90010001("账号不存在,请确认!"), + ERROR_90010002("账号或密码错误!"), + ERROR_90010003("至少要包含一个角色!"), + ERROR_90010004("管理员账号无法修改!"), + ERROR_90010005("账号被禁用,请联系管理员!"), + ERROR_90010006("活动用户不足,无法开启竞拍!"), + ERROR_90010007("旧密码不正确,请确认!"), + + + ERROR_60000001("数据不存在!"); + + public String msg; + + /** + * 生成Markdown格式文档,用于更新文档用的 + * @param args + */ + public static void main(String[] args) { + for (ApiError e : ApiError.values()) { + System.out.println("'"+e.name().replace("ERROR_", "")+"':'"+e.msg+"',"); + } + } + + /** + * 获取错误码 + * @return + */ + public Integer getCode(){ + return Integer.parseInt(this.name().replace("ERROR_", "")); + } +} diff --git a/src/main/java/com/guwan/backend/core/api/ApiRest.java b/src/main/java/com/guwan/backend/core/api/ApiRest.java new file mode 100644 index 0000000..1b93517 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/api/ApiRest.java @@ -0,0 +1,64 @@ +package com.guwan.backend.core.api; + + + +import com.guwan.backend.core.exception.ServiceException; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 数据结果返回的封装 + * @author bool + * @date 2018/11/20 09:48 + */ +@Data +@NoArgsConstructor +@ApiModel(value="接口响应", description="接口响应") +public class ApiRest{ + + /** + * 响应消息 + */ + @ApiModelProperty(value = "响应消息") + private String msg; + /** + * 响应代码 + */ + @ApiModelProperty(value = "响应代码,0为成功,1为失败", required = true) + private Integer code; + + /** + * 请求或响应body + */ + @ApiModelProperty(value = "响应内容") + protected T data; + + + /** + * 是否成功 + * @return + */ + public boolean isSuccess(){ + return code.equals(0); + } + + /** + * 构造函数 + * @param error + */ + public ApiRest(ServiceException error){ + this.code = error.getCode(); + this.msg = error.getMsg(); + } + + /** + * 构造函数 + * @param error + */ + public ApiRest(ApiError error){ + this.code = error.getCode(); + this.msg = error.msg; + } +} diff --git a/src/main/java/com/guwan/backend/core/api/controller/BaseController.java b/src/main/java/com/guwan/backend/core/api/controller/BaseController.java new file mode 100644 index 0000000..e07ee1c --- /dev/null +++ b/src/main/java/com/guwan/backend/core/api/controller/BaseController.java @@ -0,0 +1,154 @@ +package com.guwan.backend.core.api.controller; + + +import com.guwan.backend.core.api.ApiError; +import com.guwan.backend.core.api.ApiRest; +import com.guwan.backend.core.exception.ServiceException; + +/** + * 基础控制器 + * @author Dav + */ +public class BaseController { + + /** + * 成功默认消息 + */ + private static final Integer CODE_SUCCESS = 0; + private static final String MSG_SUCCESS = "操作成功!"; + + /** + * 失败默认消息 + */ + private static final Integer CODE_FAILURE = 1; + private static final String MSG_FAILURE = "请求失败!"; + + + /** + * 完成消息构造 + * @param code + * @param message + * @param data + * @param + * @return + */ + protected ApiRest message(Integer code, String message, T data){ + ApiRest response = new ApiRest<>(); + response.setCode(code); + response.setMsg(message); + if(data!=null) { + response.setData(data); + } + return response; + } + + /** + * 请求成功空数据 + * @param + * @return + */ + protected ApiRest success(){ + return message(0, "请求成功!", null); + } + + + + /** + * 请求成功,通用代码 + * @param message + * @param data + * @param + * @return + */ + protected ApiRest success(String message, T data){ + return message(CODE_SUCCESS, message, data); + } + + + /** + * 请求成功,仅内容 + * @param data + * @param + * @return + */ + protected ApiRest success(T data){ + return message(CODE_SUCCESS, MSG_SUCCESS, data); + } + + + /** + * 请求失败,完整构造 + * @param code + * @param message + * @param data + * @param + * @return + */ + protected ApiRest failure(Integer code, String message, T data){ + return message(code, message, data); + } + + /** + * 请求失败,消息和内容 + * @param message + * @param data + * @param + * @return + */ + protected ApiRest failure(String message, T data){ + return message(CODE_FAILURE, message, data); + } + + /** + * 请求失败,消息 + * @param message + * @return + */ + protected ApiRest failure(String message){ + return message(CODE_FAILURE, message, null); + } + + /** + * 请求失败,仅内容 + * @param data + * @param + * @return + */ + protected ApiRest failure(T data){ + return message(CODE_FAILURE, MSG_FAILURE, data); + } + + + /** + * 请求失败,仅内容 + * @param + * @return + */ + protected ApiRest failure(){ + return message(CODE_FAILURE, MSG_FAILURE, null); + } + + + + /** + * 请求失败,仅内容 + * @param + * @return + */ + protected ApiRest failure(ApiError error, T data){ + return message(error.getCode(), error.msg, data); + } + + + + /** + * 请求失败,仅内容 + * @param ex + * @param + * @return + */ + protected ApiRest failure(ServiceException ex){ + ApiRest apiRest = message(ex.getCode(), ex.getMsg(), null); + return apiRest; + } +} diff --git a/src/main/java/com/guwan/backend/core/api/dto/BaseDTO.java b/src/main/java/com/guwan/backend/core/api/dto/BaseDTO.java new file mode 100644 index 0000000..232cf80 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/api/dto/BaseDTO.java @@ -0,0 +1,15 @@ +package com.guwan.backend.core.api.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 请求和响应的基础类,用于处理序列化 + * @author dav + * @date 2019/3/16 15:56 + */ +@Data +public class BaseDTO implements Serializable { + +} diff --git a/src/main/java/com/guwan/backend/core/api/dto/BaseIdReqDTO.java b/src/main/java/com/guwan/backend/core/api/dto/BaseIdReqDTO.java new file mode 100644 index 0000000..54405de --- /dev/null +++ b/src/main/java/com/guwan/backend/core/api/dto/BaseIdReqDTO.java @@ -0,0 +1,27 @@ +package com.guwan.backend.core.api.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + *

+ * 主键通用请求类,用于根据ID查询 + *

+ * + * @author 聪明笨狗 + * @since 2019-04-20 12:15 + */ +@Data +@ApiModel(value="主键通用请求类", description="主键通用请求类") +public class BaseIdReqDTO extends BaseDTO { + + + @ApiModelProperty(value = "主键ID", required=true) + private String id; + + @JsonIgnore + private String userId; + +} diff --git a/src/main/java/com/guwan/backend/core/api/dto/BaseIdRespDTO.java b/src/main/java/com/guwan/backend/core/api/dto/BaseIdRespDTO.java new file mode 100644 index 0000000..e1aed5f --- /dev/null +++ b/src/main/java/com/guwan/backend/core/api/dto/BaseIdRespDTO.java @@ -0,0 +1,25 @@ +package com.guwan.backend.core.api.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + *

+ * 主键通用响应类,用于添加后返回内容 + *

+ * + * @author 聪明笨狗 + * @since 2019-04-20 12:15 + */ +@Data +@ApiModel(value="主键通用响应类", description="主键通用响应类") +@AllArgsConstructor +@NoArgsConstructor +public class BaseIdRespDTO extends BaseDTO { + + @ApiModelProperty(value = "主键ID", required=true) + private String id; +} diff --git a/src/main/java/com/guwan/backend/core/api/dto/BaseIdsReqDTO.java b/src/main/java/com/guwan/backend/core/api/dto/BaseIdsReqDTO.java new file mode 100644 index 0000000..938f5c7 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/api/dto/BaseIdsReqDTO.java @@ -0,0 +1,25 @@ +package com.guwan.backend.core.api.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * 通用ID列表类操作,用于批量删除、修改状态等 + * @author bool + * @date 2019-08-01 19:07 + */ +@Data +@ApiModel(value="删除参数", description="删除参数") +public class BaseIdsReqDTO extends BaseDTO { + + + @JsonIgnore + private String userId; + + @ApiModelProperty(value = "要删除的ID列表", required = true) + private List ids; +} diff --git a/src/main/java/com/guwan/backend/core/api/dto/BaseStateReqDTO.java b/src/main/java/com/guwan/backend/core/api/dto/BaseStateReqDTO.java new file mode 100644 index 0000000..3efce85 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/api/dto/BaseStateReqDTO.java @@ -0,0 +1,31 @@ +package com.guwan.backend.core.api.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + *

+ * 通用状态请求类,用于修改状态什么的 + *

+ * + * @author 聪明笨狗 + * @since 2019-04-20 12:15 + */ +@Data +@ApiModel(value="通用状态请求类", description="通用状态请求类") +@AllArgsConstructor +@NoArgsConstructor +public class BaseStateReqDTO extends BaseDTO { + + + @ApiModelProperty(value = "要修改对象的ID列表", required=true) + private List ids; + + @ApiModelProperty(value = "通用状态,0为正常,1为禁用", required=true) + private Integer state; +} diff --git a/src/main/java/com/guwan/backend/core/api/dto/PagingReqDTO.java b/src/main/java/com/guwan/backend/core/api/dto/PagingReqDTO.java new file mode 100644 index 0000000..2e681b5 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/api/dto/PagingReqDTO.java @@ -0,0 +1,47 @@ +package com.guwan.backend.core.api.dto; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 分页查询类 + * @param + * @author bool + */ +@ApiModel(value="分页参数", description="分页参数") +@Data +public class PagingReqDTO { + + + @ApiModelProperty(value = "当前页码", required = true, example = "1") + private Integer current; + + @ApiModelProperty(value = "每页数量", required = true, example = "10") + private Integer size; + + @ApiModelProperty(value = "查询参数") + private T params; + + @ApiModelProperty(value = "排序字符") + private String orderBy; + + @JsonIgnore + @ApiModelProperty(value = "当前用户的ID") + private String userId; + + /** + * 转换成MyBatis的简单分页对象 + * @return + */ + public Page toPage(){ + Page page = new Page(); + page.setCurrent(this.current); + page.setSize(this.size); + return page; + } + + +} diff --git a/src/main/java/com/guwan/backend/core/api/dto/PagingRespDTO.java b/src/main/java/com/guwan/backend/core/api/dto/PagingRespDTO.java new file mode 100644 index 0000000..48a0a95 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/api/dto/PagingRespDTO.java @@ -0,0 +1,30 @@ +package com.guwan.backend.core.api.dto; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; + +/** + * 分页响应类 + * @author bool + * @date 2019-07-20 15:17 + * @param + */ +public class PagingRespDTO extends Page { + + /** + * 获取页面总数量 + * @return + */ + @Override + public long getPages() { + if (this.getSize() == 0L) { + return 0L; + } else { + long pages = this.getTotal() / this.getSize(); + if (this.getTotal() % this.getSize() != 0L) { + ++pages; + } + return pages; + } + } + +} diff --git a/src/main/java/com/guwan/backend/core/api/utils/JsonConverter.java b/src/main/java/com/guwan/backend/core/api/utils/JsonConverter.java new file mode 100644 index 0000000..42443cb --- /dev/null +++ b/src/main/java/com/guwan/backend/core/api/utils/JsonConverter.java @@ -0,0 +1,48 @@ +package com.guwan.backend.core.api.utils; + +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.alibaba.fastjson.support.config.FastJsonConfig; +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +/** + * JSON数据转换器,用于转换返回消息的格式 + * @author dav + * @date 2018/9/11 19:30 + */ +public class JsonConverter { + + /** + * FastJson消息转换器 + * + * @return + */ + public static HttpMessageConverter fastConverter() { + // 定义一个convert转换消息的对象 + FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); + // 添加FastJson的配置信息 + FastJsonConfig fastJsonConfig = new FastJsonConfig(); + // 默认转换器 + fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat, + SerializerFeature.WriteNullNumberAsZero, + SerializerFeature.MapSortField, + SerializerFeature.WriteNullStringAsEmpty, + SerializerFeature.DisableCircularReferenceDetect, + SerializerFeature.WriteDateUseDateFormat, + SerializerFeature.WriteNullListAsEmpty); + fastJsonConfig.setCharset(Charset.forName("UTF-8")); + // 处理中文乱码问题 + List fastMediaTypes = new ArrayList<>(); + fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8); + fastConverter.setSupportedMediaTypes(fastMediaTypes); + // 在convert中添加配置信息 + fastConverter.setFastJsonConfig(fastJsonConfig); + + return fastConverter; + } +} diff --git a/src/main/java/com/guwan/backend/core/enums/CommonState.java b/src/main/java/com/guwan/backend/core/enums/CommonState.java new file mode 100644 index 0000000..d68f384 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/enums/CommonState.java @@ -0,0 +1,19 @@ +package com.guwan.backend.core.enums; + +/** + * 通用的状态枚举信息 + * + * @author bool + * @date 2019-09-17 17:57 + */ +public interface CommonState { + + /** + * 普通状态,正常的 + */ + Integer NORMAL = 0; + /** + * 非正常状态,禁用,下架等 + */ + Integer ABNORMAL = 1; +} diff --git a/src/main/java/com/guwan/backend/core/enums/OpenType.java b/src/main/java/com/guwan/backend/core/enums/OpenType.java new file mode 100644 index 0000000..b9f30bb --- /dev/null +++ b/src/main/java/com/guwan/backend/core/enums/OpenType.java @@ -0,0 +1,18 @@ +package com.guwan.backend.core.enums; + +/** + * 开放方式 + * @author bool + */ +public interface OpenType { + + /** + * 完全开放 + */ + Integer OPEN = 1; + + /** + * 部门开放 + */ + Integer DEPT_OPEN = 2; +} diff --git a/src/main/java/com/guwan/backend/core/exception/ServiceException.java b/src/main/java/com/guwan/backend/core/exception/ServiceException.java new file mode 100644 index 0000000..eb44cd8 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/exception/ServiceException.java @@ -0,0 +1,52 @@ +package com.guwan.backend.core.exception; + + +import com.guwan.backend.core.api.ApiError; +import com.guwan.backend.core.api.ApiRest; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ServiceException extends RuntimeException{ + + /** + * 错误码 + */ + private Integer code; + + /** + * 错误消息 + */ + private String msg; + + /** + * 从结果初始化 + * @param apiRest + */ + public ServiceException(ApiRest apiRest){ + this.code = apiRest.getCode(); + this.msg = apiRest.getMsg(); + } + + /** + * 从枚举中获取参数 + * @param apiError + */ + public ServiceException(ApiError apiError){ + this.code = apiError.getCode(); + this.msg = apiError.msg; + } + + /** + * 异常构造 + * @param msg + */ + public ServiceException(String msg){ + this.code = 1; + this.msg = msg; + } + +} diff --git a/src/main/java/com/guwan/backend/core/exception/ServiceExceptionHandler.java b/src/main/java/com/guwan/backend/core/exception/ServiceExceptionHandler.java new file mode 100644 index 0000000..5ccd91f --- /dev/null +++ b/src/main/java/com/guwan/backend/core/exception/ServiceExceptionHandler.java @@ -0,0 +1,47 @@ +package com.guwan.backend.core.exception; + + +import com.guwan.backend.core.api.ApiRest; +import org.springframework.http.HttpStatus; +import org.springframework.ui.Model; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.*; + +/** + * 统一异常处理类 + * @author bool + * @date 2019-06-21 19:27 + */ +@RestControllerAdvice +public class ServiceExceptionHandler { + + /** + * 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器 + * @param binder + */ + @InitBinder + public void initWebBinder(WebDataBinder binder){ + + } + + /** + * 把值绑定到Model中,使全局@RequestMapping可以获取到该值 + * @param model + */ + @ModelAttribute + public void addAttribute(Model model) { + + } + + /** + * 捕获ServiceException + * @param e + * @return + */ + @ExceptionHandler({com.guwan.backend.core.exception.ServiceException.class}) + @ResponseStatus(HttpStatus.OK) + public ApiRest serviceExceptionHandler(ServiceException e) { + return new ApiRest(e); + } + +} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/core/utils/CronUtils.java b/src/main/java/com/guwan/backend/core/utils/CronUtils.java new file mode 100644 index 0000000..63ee25d --- /dev/null +++ b/src/main/java/com/guwan/backend/core/utils/CronUtils.java @@ -0,0 +1,31 @@ +package com.guwan.backend.core.utils; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * 时间转换quartz表达式 + * @author bool + * @date 2020/11/29 下午3:00 + */ +public class CronUtils { + + /** + * 格式化数据 + */ + private static final String DATE_FORMAT = "ss mm HH dd MM ? yyyy"; + + /** + * 准确的时间点到表达式 + * @param date + * @return + */ + public static String dateToCron(final Date date){ + SimpleDateFormat fmt = new SimpleDateFormat(DATE_FORMAT); + String formatTimeStr = ""; + if (date != null) { + formatTimeStr = fmt.format(date); + } + return formatTimeStr; + } +} diff --git a/src/main/java/com/guwan/backend/core/utils/DateUtils.java b/src/main/java/com/guwan/backend/core/utils/DateUtils.java new file mode 100644 index 0000000..28528c0 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/utils/DateUtils.java @@ -0,0 +1,103 @@ +package com.guwan.backend.core.utils; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +/** + * 日期处理工具类 + * ClassName: DateUtils
+ * date: 2018年12月13日 下午6:34:02
+ * + * @author Bool + * @version + */ +public class DateUtils { + + /** + * + * calcExpDays:计算某个日期与当前日期相差的天数,如果计算的日期大于现在时间,将返回负数;否则返回正数
+ * @author Bool + * @param userCreateTime + * @return + * @since JDK 1.6 + */ + public static int calcExpDays(Date userCreateTime){ + + Calendar start = Calendar.getInstance(); + start.setTime(userCreateTime); + + Calendar now = Calendar.getInstance(); + now.setTime(new Date()); + + long l = now.getTimeInMillis() - start.getTimeInMillis(); + int days = new Long(l / (1000 * 60 * 60 * 24)).intValue(); + return days; + } + + + /** + * + * dateNow:获取当前时间的字符串格式,根据传入的格式化来展示.
+ * @author Bool + * @param format 日期格式化 + * @return + */ + public static String dateNow(String format) { + SimpleDateFormat fmt = new SimpleDateFormat(format); + Calendar c = new GregorianCalendar(); + return fmt.format(c.getTime()); + } + + /** + * formatDate:格式化日期,返回指定的格式
+ * @author Bool + * @param time + * @param format + * @return + */ + public static String formatDate(Date time, String format) { + SimpleDateFormat fmt = new SimpleDateFormat(format); + return fmt.format(time.getTime()); + } + + + + /** + * parseDate:将字符串转换成日期,使用:yyyy-MM-dd HH:mm:ss 来格式化 + * @author Bool + * @param date + * @return + */ + public static Date parseDate(String date) { + return parseDate(date, "yyyy-MM-dd HH:mm:ss"); + } + + + /** + * + * parseDate:将字符串转换成日期,使用指定格式化来格式化 + * @author Bool + * @param date + * @param pattern + * @return + */ + public static Date parseDate(String date, String pattern) { + + if (pattern==null) { + pattern = "yyyy-MM-dd HH:mm:ss"; + } + + SimpleDateFormat fmt = new SimpleDateFormat(pattern); + + try { + + return fmt.parse(date); + } catch (Exception ex) { + ex.printStackTrace(); + } + return null; + + } +} diff --git a/src/main/java/com/guwan/backend/core/utils/IpUtils.java b/src/main/java/com/guwan/backend/core/utils/IpUtils.java new file mode 100644 index 0000000..e1fecf7 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/utils/IpUtils.java @@ -0,0 +1,65 @@ +package com.guwan.backend.core.utils; + + +import javax.servlet.http.HttpServletRequest; + +/** + * IP获取工具类,用户获取网络请求过来的真实IP + * ClassName: IpUtils
+ * date: 2018年2月13日 下午7:27:52
+ * + * @author Bool + * @version + */ +public class IpUtils { + + + /** + * + * getClientIp:通过请求获取客户端的真实IP地址 + * @author Bool + * @param request + * @return + */ + public static String extractClientIp(HttpServletRequest request) { + + String ip = null; + + //X-Forwarded-For:Squid 服务代理 + String ipAddresses = request.getHeader("X-Forwarded-For"); + + if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + //Proxy-Client-IP:apache 服务代理 + ipAddresses = request.getHeader("Proxy-Client-IP"); + } + + if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + //WL-Proxy-Client-IP:weblogic 服务代理 + ipAddresses = request.getHeader("WL-Proxy-Client-IP"); + } + + if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + //HTTP_CLIENT_IP:有些代理服务器 + ipAddresses = request.getHeader("HTTP_CLIENT_IP"); + } + + if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + //X-Real-IP:nginx服务代理 + ipAddresses = request.getHeader("X-Real-IP"); + } + + //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP + if (ipAddresses != null && ipAddresses.length() != 0) { + ip = ipAddresses.split(",")[0]; + } + + //还是不能获取到,最后再通过request.getRemoteAddr();获取 + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + ip = request.getRemoteAddr(); + } + + return ip; + } + + +} diff --git a/src/main/java/com/guwan/backend/core/utils/Reflections.java b/src/main/java/com/guwan/backend/core/utils/Reflections.java new file mode 100644 index 0000000..d3af9ac --- /dev/null +++ b/src/main/java/com/guwan/backend/core/utils/Reflections.java @@ -0,0 +1,319 @@ +/** + * Copyright (c) 2005-2012 springside.org.cn + */ +package com.guwan.backend.core.utils; + +import lombok.extern.log4j.Log4j2; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.springframework.util.Assert; + +import java.lang.reflect.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 反射工具类. + * 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. + * @author calvin + * @version 2016-01-15 + */ +@Log4j2 +public class Reflections { + + private static final String SETTER_PREFIX = "set"; + + private static final String GETTER_PREFIX = "get"; + + private static final String CGLIB_CLASS_SEPARATOR = "$$"; + + + /** + * 获取类的所有属性,包括父类 + * + * @param object + * @return + */ + public static Field[] getAllFields(Object object) { + Class clazz = object.getClass(); + List fieldList = new ArrayList<>(); + while (clazz != null) { + fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()))); + clazz = clazz.getSuperclass(); + } + Field[] fields = new Field[fieldList.size()]; + fieldList.toArray(fields); + return fields; + } + + + /** + * 调用Getter方法. + * 支持多级,如:对象名.对象名.方法 + */ + public static Object invokeGetter(Object obj, String propertyName) { + Object object = obj; + for (String name : StringUtils.split(propertyName, ".")){ + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); + object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); + } + return object; + } + + /** + * 调用Setter方法, 仅匹配方法名。 + * 支持多级,如:对象名.对象名.方法 + */ + public static void invokeSetter(Object obj, String propertyName, Object value) { + Object object = obj; + String[] names = StringUtils.split(propertyName, "."); + for (int i=0; i[] parameterTypes, + final Object[] args) { + Method method = getAccessibleMethod(obj, methodName, parameterTypes); + if (method == null) { + throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]"); + } + + try { + return method.invoke(obj, args); + } catch (Exception e) { + throw convertReflectionExceptionToUnchecked(e); + } + } + + /** + * 直接调用对象方法, 无视private/protected修饰符, + * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用. + * 只匹配函数名,如果有多个同名函数调用第一个。 + */ + public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) { + Method method = getAccessibleMethodByName(obj, methodName); + if (method == null) { + throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]"); + } + + try { + return method.invoke(obj, args); + } catch (Exception e) { + throw convertReflectionExceptionToUnchecked(e); + } + } + + /** + * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问. + * + * 如向上转型到Object仍无法找到, 返回null. + */ + public static Field getAccessibleField(final Object obj, final String fieldName) { + Validate.notNull(obj, "object can't be null"); + Validate.notBlank(fieldName, "fieldName can't be blank"); + for (Class superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) { + try { + Field field = superClass.getDeclaredField(fieldName); + makeAccessible(field); + return field; + } catch (NoSuchFieldException e) {//NOSONAR + // Field不在当前类定义,继续向上转型 + continue;// new add + } + } + return null; + } + + /** + * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + * 匹配函数名+参数类型。 + * + * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) + */ + public static Method getAccessibleMethod(final Object obj, final String methodName, + final Class... parameterTypes) { + Validate.notNull(obj, "object can't be null"); + Validate.notBlank(methodName, "methodName can't be blank"); + + for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { + try { + Method method = searchType.getDeclaredMethod(methodName, parameterTypes); + makeAccessible(method); + return method; + } catch (NoSuchMethodException e) { + // Method不在当前类定义,继续向上转型 + continue;// new add + } + } + return null; + } + + /** + * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + * 只匹配函数名。 + * + * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) + */ + public static Method getAccessibleMethodByName(final Object obj, final String methodName) { + Validate.notNull(obj, "object can't be null"); + Validate.notBlank(methodName, "methodName can't be blank"); + + for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { + Method[] methods = searchType.getDeclaredMethods(); + for (Method method : methods) { + if (method.getName().equals(methodName)) { + makeAccessible(method); + return method; + } + } + } + return null; + } + + /** + * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 + */ + public static void makeAccessible(Method method) { + if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) + && !method.isAccessible()) { + method.setAccessible(true); + } + } + + /** + * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 + */ + public static void makeAccessible(Field field) { + if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier + .isFinal(field.getModifiers())) && !field.isAccessible()) { + field.setAccessible(true); + } + } + + /** + * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处 + * 如无法找到, 返回Object.class. + * eg. + * public UserDao extends HibernateDao + * + * @param clazz The class to introspect + * @return the first generic declaration, or Object.class if cannot be determined + */ + @SuppressWarnings("unchecked") + public static Class getClassGenricType(final Class clazz) { + return getClassGenricType(clazz, 0); + } + + /** + * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. + * 如无法找到, 返回Object.class. + * + * 如public UserDao extends HibernateDao + * + * @param clazz clazz The class to introspect + * @param index the Index of the generic ddeclaration,start from 0. + * @return the index generic declaration, or Object.class if cannot be determined + */ + public static Class getClassGenricType(final Class clazz, final int index) { + + Type genType = clazz.getGenericSuperclass(); + + if (!(genType instanceof ParameterizedType)) { + log.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType"); + return Object.class; + } + + Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); + + if (index >= params.length || index < 0) { + log.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + + params.length); + return Object.class; + } + if (!(params[index] instanceof Class)) { + log.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter"); + return Object.class; + } + + return (Class) params[index]; + } + + public static Class getUserClass(Object instance) { + Assert.notNull(instance, "Instance must not be null"); + Class clazz = instance.getClass(); + if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) { + Class superClass = clazz.getSuperclass(); + if (superClass != null && !Object.class.equals(superClass)) { + return superClass; + } + } + return clazz; + + } + + /** + * 将反射时的checked exception转换为unchecked exception. + */ + public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) { + if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException + || e instanceof NoSuchMethodException) { + return new IllegalArgumentException(e); + } else if (e instanceof InvocationTargetException) { + return new RuntimeException(((InvocationTargetException) e).getTargetException()); + } else if (e instanceof RuntimeException) { + return (RuntimeException) e; + } + return new RuntimeException("Unexpected Checked Exception.", e); + } +} diff --git a/src/main/java/com/guwan/backend/core/utils/SpringUtils.java b/src/main/java/com/guwan/backend/core/utils/SpringUtils.java new file mode 100644 index 0000000..cd41c07 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/utils/SpringUtils.java @@ -0,0 +1,32 @@ +package com.guwan.backend.core.utils; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * Spring获取工具 + * + * @author bool + * @date 2019-12-09 15:55 + */ +@Component +public class SpringUtils implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext context) throws BeansException { + applicationContext = context; + } + + public static T getBean(Class tClass) { + return applicationContext.getBean(tClass); + } + + public static T getBean(String name, Class type) { + return applicationContext.getBean(name, type); + } + +} diff --git a/src/main/java/com/guwan/backend/core/utils/StringUtils.java b/src/main/java/com/guwan/backend/core/utils/StringUtils.java new file mode 100644 index 0000000..cd6362f --- /dev/null +++ b/src/main/java/com/guwan/backend/core/utils/StringUtils.java @@ -0,0 +1,39 @@ +package com.guwan.backend.core.utils; + +import java.util.Map; + +/** + * 字符串常用工具类 + * @author bool + * @date 2019-05-15 11:40 + */ +public class StringUtils { + + /** + * 判断是否为空字符 + * @param str + * @return + */ + public static boolean isBlank(String str){ + return str==null || "".equals(str); + } + + + /** + * 将MAP转换成一个xml格式,格式为value... + * @param params + * @return + */ + public static String mapToXml(Map params){ + StringBuffer sb = new StringBuffer(""); + for(String key:params.keySet()){ + sb.append("<") + .append(key).append(">") + .append(params.get(key)) + .append(""); + } + + sb.append(""); + return sb.toString(); + } +} diff --git a/src/main/java/com/guwan/backend/core/utils/excel/ExportExcel.java b/src/main/java/com/guwan/backend/core/utils/excel/ExportExcel.java new file mode 100644 index 0000000..4eeb79c --- /dev/null +++ b/src/main/java/com/guwan/backend/core/utils/excel/ExportExcel.java @@ -0,0 +1,391 @@ +/** + * Copyright © 2015-2020 JeePlus All rights reserved. + */ +package com.guwan.backend.core.utils.excel; + +import com.google.common.collect.Lists; + +import com.guwan.backend.core.utils.Reflections; +import com.guwan.backend.core.utils.excel.annotation.ExcelField; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; +import org.apache.poi.xssf.usermodel.XSSFRichTextString; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.URLEncoder; +import java.util.*; + +/** + * 导出Excel文件(导出“XLSX”格式,支持大数据量导出 @see org.apache.poi.ss.SpreadsheetVersion) + * @author jeeplus + * @version 2016-04-21 + */ +public class ExportExcel { + + private static Logger log = LoggerFactory.getLogger(ExportExcel.class); + + /** + * 工作薄对象 + */ + private SXSSFWorkbook wb; + + /** + * 工作表对象 + */ + private Sheet sheet; + + /** + * 样式列表 + */ + private Map styles; + + /** + * 当前行号 + */ + private int rownum; + + /** + * 注解列表(Object[]{ ExcelField, Field/Method }) + */ + List annotationList = Lists.newArrayList(); + + /** + * 构造函数 + * @param title 表格标题,传“空值”,表示无标题 + * @param cls 实体对象,通过annotation.ExportField获取标题 + */ + public ExportExcel(String title, Class cls){ + this(title, cls, 1); + } + + /** + * 构造函数 + * @param title 表格标题,传“空值”,表示无标题 + * @param cls 实体对象,通过annotation.ExportField获取标题 + * @param type 导出类型(1:导出数据;2:导出模板) + * @param groups 导入分组 + */ + public ExportExcel(String title, Class cls, int type, int... groups){ + // Get annotation field + Field[] fs = cls.getDeclaredFields(); + for (Field f : fs){ + ExcelField ef = f.getAnnotation(ExcelField.class); + if (ef != null && (ef.type()==0 || ef.type()==type)){ + if (groups!=null && groups.length>0){ + boolean inGroup = false; + for (int g : groups){ + if (inGroup){ + break; + } + for (int efg : ef.groups()){ + if (g == efg){ + inGroup = true; + annotationList.add(new Object[]{ef, f}); + break; + } + } + } + }else{ + annotationList.add(new Object[]{ef, f}); + } + } + } + // Get annotation method + Method[] ms = cls.getDeclaredMethods(); + for (Method m : ms){ + ExcelField ef = m.getAnnotation(ExcelField.class); + if (ef != null && (ef.type()==0 || ef.type()==type)){ + if (groups!=null && groups.length>0){ + boolean inGroup = false; + for (int g : groups){ + if (inGroup){ + break; + } + for (int efg : ef.groups()){ + if (g == efg){ + inGroup = true; + annotationList.add(new Object[]{ef, m}); + break; + } + } + } + }else{ + annotationList.add(new Object[]{ef, m}); + } + } + } + // Field sorting + Collections.sort(annotationList, new Comparator() { + @Override + public int compare(Object[] o1, Object[] o2) { + /*return new Integer(((ExcelField)o1[0]).sort()).compareTo( + new Integer(((ExcelField)o2[0]).sort()));*/ + return Integer.compare(((ExcelField) o1[0]).sort(), ((ExcelField) o2[0]).sort()); + } + }); + // Initialize + List headerList = Lists.newArrayList(); + for (Object[] os : annotationList){ + String t = ((ExcelField)os[0]).title(); + // 如果是导出,则去掉注释 + if (type==1){ + String[] ss = StringUtils.split(t, "**", 2); + if (ss.length==2){ + t = ss[0]; + } + } + headerList.add(t); + } + initialize(title, headerList); + } + /** + * 初始化函数 + * @param title 表格标题,传“空值”,表示无标题 + * @param headerList 表头列表 + */ + private void initialize(String title, List headerList) { + this.wb = new SXSSFWorkbook(500); + this.sheet = wb.createSheet("Export"); + this.styles = createStyles(wb); + // Create title + if (StringUtils.isNotBlank(title)){ + Row titleRow = sheet.createRow(rownum++); + titleRow.setHeightInPoints(30); + Cell titleCell = titleRow.createCell(0); + titleCell.setCellStyle(styles.get("title")); + titleCell.setCellValue(title); + sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), + titleRow.getRowNum(), titleRow.getRowNum(), headerList.size()-1)); + } + // Create header + if (headerList == null){ + throw new RuntimeException("headerList not null!"); + } + Row headerRow = sheet.createRow(rownum++); + headerRow.setHeightInPoints(16); + for (int i = 0; i < headerList.size(); i++) { + Cell cell = headerRow.createCell(i); + cell.setCellStyle(styles.get("header")); + String[] ss = StringUtils.split(headerList.get(i), "**", 2); + if (ss.length==2){ + cell.setCellValue(ss[0]); + Comment comment = this.sheet.createDrawingPatriarch().createCellComment( + new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6)); + comment.setString(new XSSFRichTextString(ss[1])); + cell.setCellComment(comment); + }else{ + cell.setCellValue(headerList.get(i)); + } + sheet.autoSizeColumn(i); + } + for (int i = 0; i < headerList.size(); i++) { + int colWidth = sheet.getColumnWidth(i)*2; + sheet.setColumnWidth(i, colWidth < 3000 ? 3000 : colWidth); + } + log.debug("Initialize success."); + } + + /** + * 创建表格样式 + * @param wb 工作薄对象 + * @return 样式列表 + */ + private Map createStyles(Workbook wb) { + Map styles = new HashMap<>(16); + + CellStyle style = wb.createCellStyle(); + style.setAlignment(CellStyle.ALIGN_CENTER); + style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); + Font titleFont = wb.createFont(); + titleFont.setFontName("Arial"); + titleFont.setFontHeightInPoints((short) 16); + titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD); + style.setFont(titleFont); + styles.put("title", style); + + style = wb.createCellStyle(); + style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); + style.setBorderRight(CellStyle.BORDER_THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(CellStyle.BORDER_THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(CellStyle.BORDER_THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(CellStyle.BORDER_THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + style.setFont(dataFont); + styles.put("data", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(CellStyle.ALIGN_LEFT); + styles.put("data1", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(CellStyle.ALIGN_CENTER); + styles.put("data2", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(CellStyle.ALIGN_RIGHT); + styles.put("data3", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); +// style.setWrapText(true); + style.setAlignment(CellStyle.ALIGN_CENTER); + style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setFillPattern(CellStyle.SOLID_FOREGROUND); + Font headerFont = wb.createFont(); + headerFont.setFontName("Arial"); + headerFont.setFontHeightInPoints((short) 10); + headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD); + headerFont.setColor(IndexedColors.WHITE.getIndex()); + style.setFont(headerFont); + styles.put("header", style); + + return styles; + } + + /** + * 添加一行 + * @return 行对象 + */ + public Row addRow(){ + return sheet.createRow(rownum++); + } + + + /** + * 添加一个单元格 + * @param row 添加的行 + * @param column 添加列号 + * @param val 添加值 + * @return 单元格对象 + */ + public Cell addCell(Row row, int column, Object val){ + return this.addCell(row, column, val, 0, Class.class); + } + + /** + * 添加一个单元格 + * @param row 添加的行 + * @param column 添加列号 + * @param val 添加值 + * @param align 对齐方式(1:靠左;2:居中;3:靠右) + * @return 单元格对象 + */ + public Cell addCell(Row row, int column, Object val, int align, Class fieldType){ + Cell cell = row.createCell(column); + CellStyle style = styles.get("data"+(align>=1&&align<=3?align:"")); + try { + if (val == null){ + cell.setCellValue(""); + } else if (val instanceof String) { + cell.setCellValue((String) val); + } else if (val instanceof Integer) { + cell.setCellValue((Integer) val); + } else if (val instanceof Long) { + cell.setCellValue((Long) val); + } else if (val instanceof Double) { + cell.setCellValue((Double) val); + } else if (val instanceof Float) { + cell.setCellValue((Float) val); + } else if (val instanceof Date) { + DataFormat format = wb.createDataFormat(); + style.setDataFormat(format.getFormat("yyyy-MM-dd")); + cell.setCellValue((Date) val); + } else { + if (fieldType != Class.class){ + cell.setCellValue((String)fieldType.getMethod("setValue", Object.class).invoke(null, val)); + }else{ + cell.setCellValue((String)Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(), + "fieldtype."+val.getClass().getSimpleName()+"Type")).getMethod("setValue", Object.class).invoke(null, val)); + } + } + } catch (Exception ex) { + log.info("Set cell value ["+row.getRowNum()+","+column+"] error: " + ex.toString()); + cell.setCellValue(val.toString()); + } + cell.setCellStyle(style); + return cell; + } + + /** + * 添加数据(通过annotation.ExportField添加数据) + * @return list 数据列表 + */ + public ExportExcel setDataList(List list){ + for (E e : list){ + int colunm = 0; + Row row = this.addRow(); + StringBuilder sb = new StringBuilder(); + for (Object[] os : annotationList){ + ExcelField ef = (ExcelField)os[0]; + Object val = null; + try{ + if (StringUtils.isNotBlank(ef.value())){ + val = Reflections.invokeGetter(e, ef.value()); + }else{ + if (os[1] instanceof Field){ + val = Reflections.invokeGetter(e, ((Field)os[1]).getName()); + }else if (os[1] instanceof Method){ + val = Reflections.invokeMethod(e, ((Method)os[1]).getName(), new Class[] {}, new Object[] {}); + } + } + }catch(Exception ex) { + log.info(ex.toString()); + val = ""; + } + this.addCell(row, colunm++, val, ef.align(), ef.fieldType()); + sb.append(val + ", "); + } + log.debug("Write success: ["+row.getRowNum()+"] "+sb.toString()); + } + return this; + } + + /** + * 输出数据流 + * @param os 输出数据流 + */ + public ExportExcel write(OutputStream os) throws IOException{ + wb.write(os); + return this; + } + + /** + * 输出到客户端 + * @param fileName 输出文件名 + */ + public ExportExcel write(HttpServletResponse response, String fileName) throws IOException{ + response.reset(); + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setContentType("application/octet-stream; charset=utf-8"); + response.addHeader("Content-Disposition", "attachment; filename="+ URLEncoder.encode(fileName, "utf-8")); + write(response.getOutputStream()); + return this; + } + + /** + * 清理临时文件 + */ + public ExportExcel dispose(){ + wb.dispose(); + return this; + } + +} diff --git a/src/main/java/com/guwan/backend/core/utils/excel/ImportExcel.java b/src/main/java/com/guwan/backend/core/utils/excel/ImportExcel.java new file mode 100644 index 0000000..2285e02 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/utils/excel/ImportExcel.java @@ -0,0 +1,305 @@ +/** + * Copyright © 2015-2020 JeePlus All rights reserved. + */ +package com.guwan.backend.core.utils.excel; + +import com.google.common.collect.Lists; + +import com.guwan.backend.core.utils.Reflections; +import com.guwan.backend.core.utils.excel.annotation.ExcelField; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.hssf.usermodel.HSSFDateUtil; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.text.NumberFormat; +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; + +/** + * 导入Excel文件(支持“XLS”和“XLSX”格式) + * @author jeeplus + * @version 2016-03-10 + */ +public class ImportExcel { + + private static Logger log = LoggerFactory.getLogger(ImportExcel.class); + + /** + * 工作薄对象 + */ + private Workbook wb; + + /** + * 工作表对象 + */ + private Sheet sheet; + + /** + * 标题行号 + */ + private int headerNum; + + + + /** + * 构造函数 + * @param multipartFile 导入文件对象 + * @param headerNum 标题行号,数据行号=标题行号+1 + * @param sheetIndex 工作表编号 + * @throws InvalidFormatException + * @throws IOException + */ + public ImportExcel(MultipartFile multipartFile, int headerNum, int sheetIndex) + throws InvalidFormatException, IOException { + this(multipartFile.getOriginalFilename(), multipartFile.getInputStream(), headerNum, sheetIndex); + } + + /** + * 构造函数 + * @param is 导入文件对象 + * @param headerNum 标题行号,数据行号=标题行号+1 + * @param sheetIndex 工作表编号 + * @throws InvalidFormatException + * @throws IOException + */ + public ImportExcel(String fileName, InputStream is, int headerNum, int sheetIndex) + throws IOException { + if (StringUtils.isBlank(fileName)){ + throw new RuntimeException("导入文档为空!"); + }else if(fileName.toLowerCase().endsWith("xls")){ + this.wb = new HSSFWorkbook(is); + }else if(fileName.toLowerCase().endsWith("xlsx")){ + this.wb = new XSSFWorkbook(is); + }else{ + throw new RuntimeException("文档格式不正确!"); + } + if (this.wb.getNumberOfSheets() List getDataList(Class cls, int... groups) throws InstantiationException, IllegalAccessException{ + List annotationList = Lists.newArrayList(); + // Get annotation field + Field[] fs = cls.getDeclaredFields(); + for (Field f : fs){ + ExcelField ef = f.getAnnotation(ExcelField.class); + if (ef != null && (ef.type()==0 || ef.type()==2)){ + if (groups!=null && groups.length>0){ + boolean inGroup = false; + for (int g : groups){ + if (inGroup){ + break; + } + for (int efg : ef.groups()){ + if (g == efg){ + inGroup = true; + annotationList.add(new Object[]{ef, f}); + break; + } + } + } + }else{ + annotationList.add(new Object[]{ef, f}); + } + } + } + // Get annotation method + Method[] ms = cls.getDeclaredMethods(); + for (Method m : ms){ + ExcelField ef = m.getAnnotation(ExcelField.class); + if (ef != null && (ef.type()==0 || ef.type()==2)){ + if (groups!=null && groups.length>0){ + boolean inGroup = false; + for (int g : groups){ + if (inGroup){ + break; + } + for (int efg : ef.groups()){ + if (g == efg){ + inGroup = true; + annotationList.add(new Object[]{ef, m}); + break; + } + } + } + }else{ + annotationList.add(new Object[]{ef, m}); + } + } + } + // Field sorting + Collections.sort(annotationList, new Comparator() { + @Override + public int compare(Object[] o1, Object[] o2) { +// return new Integer(((ExcelField)o1[0]).sort()).compareTo( +// new Integer(((ExcelField)o2[0]).sort())); + return Integer.compare(((ExcelField) o1[0]).sort(), ((ExcelField) o2[0]).sort()); + } + }); + // Get excel data + List dataList = Lists.newArrayList(); + for (int i = this.getDataRowNum(); i < this.getLastDataRowNum(); i++) { + E e = (E)cls.newInstance(); + int column = 0; + Row row = this.getRow(i); + StringBuilder sb = new StringBuilder(); + for (Object[] os : annotationList){ + Object val = this.getCellValue(row, column++); + if (val != null){ + ExcelField ef = (ExcelField)os[0]; + // Get param type and type cast + Class valType = Class.class; + if (os[1] instanceof Field){ + valType = ((Field)os[1]).getType(); + }else if (os[1] instanceof Method){ + Method method = ((Method)os[1]); + if ("get".equals(method.getName().substring(0, 3))){ + valType = method.getReturnType(); + }else if("set".equals(method.getName().substring(0, 3))){ + valType = ((Method)os[1]).getParameterTypes()[0]; + } + } + //log.debug("Import value type: ["+i+","+column+"] " + valType); + try { + //如果导入的java对象,需要在这里自己进行变换。 + if (valType == String.class){ + String s = String.valueOf(val.toString()); + if(StringUtils.endsWith(s, ".0")){ + val = StringUtils.substringBefore(s, ".0"); + }else{ + val = String.valueOf(val.toString()); + } + }else if (valType == Integer.class){ + val = Double.valueOf(val.toString()).intValue(); + }else if (valType == Long.class){ + val = Double.valueOf(val.toString()).longValue(); + }else if (valType == Double.class){ + val = Double.valueOf(val.toString()); + }else if (valType == Float.class){ + val = Float.valueOf(val.toString()); + }else if (valType == Date.class){ + SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); + val=sdf.parse(val.toString()); + }else{ + if (ef.fieldType() != Class.class){ + val = ef.fieldType().getMethod("getValue", String.class).invoke(null, val.toString()); + }else{ + val = Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(), + "fieldtype."+valType.getSimpleName()+"Type")).getMethod("getValue", String.class).invoke(null, val.toString()); + } + } + } catch (Exception ex) { + log.info("Get cell value ["+i+","+column+"] error: " + ex.toString()); + val = null; + } + // set entity value + if (os[1] instanceof Field){ + Reflections.invokeSetter(e, ((Field)os[1]).getName(), val); + }else if (os[1] instanceof Method){ + String mthodName = ((Method)os[1]).getName(); + if ("get".equals(mthodName.substring(0, 3))){ + mthodName = "set"+StringUtils.substringAfter(mthodName, "get"); + } + Reflections.invokeMethod(e, mthodName, new Class[] {valType}, new Object[] {val}); + } + } + sb.append(val+", "); + } + dataList.add(e); + log.debug("Read success: ["+i+"] "+sb.toString()); + } + return dataList; + } + +} diff --git a/src/main/java/com/guwan/backend/core/utils/excel/annotation/ExcelField.java b/src/main/java/com/guwan/backend/core/utils/excel/annotation/ExcelField.java new file mode 100644 index 0000000..9da9b17 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/utils/excel/annotation/ExcelField.java @@ -0,0 +1,59 @@ +/** + * Copyright © 2015-2020 JeePlus All rights reserved. + */ +package com.guwan.backend.core.utils.excel.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Excel注解定义 + * @author jeeplus + * @version 2016-03-10 + */ +@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ExcelField { + + /** + * 导出字段名(默认调用当前字段的“get”方法,如指定导出字段为对象,请填写“对象名.对象属性”,例:“area.name”、“office.name”) + */ + String value() default ""; + + /** + * 导出字段标题(需要添加批注请用“**”分隔,标题**批注,仅对导出模板有效) + */ + String title(); + + /** + * 字段类型(0:导出导入;1:仅导出;2:仅导入) + */ + int type() default 0; + + /** + * 导出字段对齐方式(0:自动;1:靠左;2:居中;3:靠右) + */ + int align() default 0; + + /** + * 导出字段字段排序(升序) + */ + int sort() default 0; + + /** + * 如果是字典类型,请设置字典的type值 + */ + String dictType() default ""; + + /** + * 反射类型 + */ + Class fieldType() default Class.class; + + /** + * 字段归属组(根据分组导出导入) + */ + int[] groups() default {}; +} diff --git a/src/main/java/com/guwan/backend/core/utils/excel/fieldtype/ListType.java b/src/main/java/com/guwan/backend/core/utils/excel/fieldtype/ListType.java new file mode 100644 index 0000000..3e19ce9 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/utils/excel/fieldtype/ListType.java @@ -0,0 +1,57 @@ +/** + * Copyright © 2015-2020 JeePlus All rights reserved. + */ +package com.guwan.backend.core.utils.excel.fieldtype; + +import com.google.common.collect.Lists; +import com.guwan.backend.core.utils.StringUtils; + + +import java.util.List; + +/** + * 字段类型转换 + * @author jeeplus + * @version 2016-5-29 + */ +public class ListType { + + /** + * 获取对象值(导入) + */ + public static Object getValue(String val) { + List list = Lists.newArrayList(); + if(!StringUtils.isBlank(val)) { + for (String s : val.split(",")) { + list.add(s); + } + } + return list; + } + + /** + * 设置对象值(导出) + */ + public static String setValue(Object val) { + if (val != null){ + List list = (List)val; + StringBuffer sb = null; + for (String item: list){ + if(StringUtils.isBlank(item)){ + continue; + } + if(sb == null){ + sb = new StringBuffer(item); + }else{ + sb.append(",").append(item); + } + } + + if(sb!=null) { + return sb.toString().replace("[]", ""); + } + } + return ""; + } + +} diff --git a/src/main/java/com/guwan/backend/core/utils/file/Md5Util.java b/src/main/java/com/guwan/backend/core/utils/file/Md5Util.java new file mode 100644 index 0000000..2c920b4 --- /dev/null +++ b/src/main/java/com/guwan/backend/core/utils/file/Md5Util.java @@ -0,0 +1,37 @@ +package com.guwan.backend.core.utils.file; + +import java.security.MessageDigest; + + +/** + * MD5工具类 + * ClassName: MD5Util
+ * date: 2018年1月13日 下午6:54:53
+ * + * @author Bool + * @version + */ +public class Md5Util { + + + /** + * 简单MD5 + * @param str + * @return + */ + public static String md5(String str) { + + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] array = md.digest(str.getBytes("UTF-8")); + StringBuilder sb = new StringBuilder(); + for (byte item : array) { + sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3)); + } + return sb.toString(); + }catch(Exception e) { + return null; + } + } + +} diff --git a/src/main/java/com/guwan/backend/core/utils/passwd/PassHandler.java b/src/main/java/com/guwan/backend/core/utils/passwd/PassHandler.java new file mode 100644 index 0000000..c9869ef --- /dev/null +++ b/src/main/java/com/guwan/backend/core/utils/passwd/PassHandler.java @@ -0,0 +1,58 @@ +package com.guwan.backend.core.utils.passwd; + + + +import com.guwan.backend.core.utils.file.Md5Util; +import org.apache.commons.lang3.RandomStringUtils; + +/** + * 通用的密码处理类,用于生成密码和校验密码 + * ClassName: PassGenerator
+ * date: 2017年12月13日 下午7:13:03
+ * + * @author Bool + * @version + */ +public class PassHandler { + + /** + * checkPass:校验密码是否一致 + * @author Bool + * @param inputPass 用户传入的密码 + * @param salt 数据库保存的密码随机码 + * @param pass 数据库保存的密码MD5 + * @return + */ + public static boolean checkPass(String inputPass , String salt , String pass){ + String pwdMd5 = Md5Util.md5(inputPass); + return Md5Util.md5(pwdMd5 + salt).equals(pass); + } + + + /** + * + * buildPassword:用于用户注册时产生一个密码 + * @author Bool + * @param inputPass 输入的密码 + * @return PassInfo 返回一个密码对象,记得保存 + */ + public static PassInfo buildPassword(String inputPass) { + + //产生一个6位数的随机码 + String salt = RandomStringUtils.randomAlphabetic(6); + //加密后的密码 + String encryptPassword = Md5Util.md5(Md5Util.md5(inputPass)+salt); + //返回对象 + return new PassInfo(salt,encryptPassword); + } + + + public static void main(String[] args) { + + PassInfo info = buildPassword("190601"); + + System.out.println(info.getPassword()); + System.out.println(info.getSalt()); + } + +} diff --git a/src/main/java/com/guwan/backend/core/utils/passwd/PassInfo.java b/src/main/java/com/guwan/backend/core/utils/passwd/PassInfo.java new file mode 100644 index 0000000..8b1e4df --- /dev/null +++ b/src/main/java/com/guwan/backend/core/utils/passwd/PassInfo.java @@ -0,0 +1,38 @@ +package com.guwan.backend.core.utils.passwd; + +/** + * 密码实体 + * ClassName: PassInfo
+ * date: 2018年2月13日 下午7:13:50
+ * + * @author Bool + * @version + */ +public class PassInfo { + + //密码随机串码 + private String salt; + + //MD5后的密码 + private String password; + + public PassInfo(String salt, String password) { + super(); + this.salt = salt; + this.password = password; + } + + public String getSalt() { + return salt; + } + public void setSalt(String salt) { + this.salt = salt; + } + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } +} + diff --git a/src/main/java/com/guwan/backend/face/entity/UserCompareInfo.java b/src/main/java/com/guwan/backend/face/entity/UserCompareInfo.java index 938a01a..436aa7c 100644 --- a/src/main/java/com/guwan/backend/face/entity/UserCompareInfo.java +++ b/src/main/java/com/guwan/backend/face/entity/UserCompareInfo.java @@ -1,7 +1,8 @@ package com.guwan.backend.face.entity; -import com.guwan.face.util.UserInfo; + +import com.guwan.backend.face.util.UserInfo; import lombok.Data; diff --git a/src/main/java/com/guwan/backend/face/enums/ErrorCodeEnum.java b/src/main/java/com/guwan/backend/face/enums/ErrorCodeEnum.java index e8c76e8..ce93767 100644 --- a/src/main/java/com/guwan/backend/face/enums/ErrorCodeEnum.java +++ b/src/main/java/com/guwan/backend/face/enums/ErrorCodeEnum.java @@ -1,7 +1,8 @@ package com.guwan.backend.face.enums; -import com.guwan.face.rpc.ErrorCode; + +import com.guwan.backend.face.rpc.ErrorCode; import lombok.Getter; diff --git a/src/main/java/com/guwan/backend/face/face/FaceRecognize.java b/src/main/java/com/guwan/backend/face/face/FaceRecognize.java index 93edc13..2115cde 100644 --- a/src/main/java/com/guwan/backend/face/face/FaceRecognize.java +++ b/src/main/java/com/guwan/backend/face/face/FaceRecognize.java @@ -6,8 +6,9 @@ import com.arcsoft.face.enums.ErrorInfo; import com.arcsoft.face.enums.ExtractType; import com.arcsoft.face.toolkit.ImageFactory; import com.arcsoft.face.toolkit.ImageInfo; -import com.guwan.face.config.ArcFaceAutoConfiguration; -import com.guwan.face.factory.FaceEngineFactory; + +import com.guwan.backend.face.config.ArcFaceAutoConfiguration; +import com.guwan.backend.face.factory.FaceEngineFactory; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; diff --git a/src/main/java/com/guwan/backend/face/factory/FaceEngineFactory.java b/src/main/java/com/guwan/backend/face/factory/FaceEngineFactory.java index 4eed0b3..5d56ecf 100644 --- a/src/main/java/com/guwan/backend/face/factory/FaceEngineFactory.java +++ b/src/main/java/com/guwan/backend/face/factory/FaceEngineFactory.java @@ -3,9 +3,10 @@ package com.guwan.backend.face.factory; import com.arcsoft.face.EngineConfiguration; import com.arcsoft.face.FaceEngine; import com.arcsoft.face.enums.ErrorInfo; -import com.guwan.face.config.ArcFaceAutoConfiguration; -import com.guwan.face.enums.ErrorCodeEnum; -import com.guwan.face.rpc.BusinessException; + +import com.guwan.backend.face.config.ArcFaceAutoConfiguration; +import com.guwan.backend.face.enums.ErrorCodeEnum; +import com.guwan.backend.face.rpc.BusinessException; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.commons.pool2.BasePooledObjectFactory; diff --git a/src/main/java/com/guwan/backend/face/rpc/GlobalExceptionHandler.java b/src/main/java/com/guwan/backend/face/rpc/GlobalExceptionHandler.java index 3995898..63c7213 100644 --- a/src/main/java/com/guwan/backend/face/rpc/GlobalExceptionHandler.java +++ b/src/main/java/com/guwan/backend/face/rpc/GlobalExceptionHandler.java @@ -1,7 +1,9 @@ +/* package com.guwan.backend.face.rpc; -import com.guwan.face.enums.ErrorCodeEnum; + +import com.guwan.backend.face.enums.ErrorCodeEnum; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -11,9 +13,11 @@ import org.springframework.web.bind.annotation.RestControllerAdvice; public class GlobalExceptionHandler{ - /** + */ +/** * 自定义异常 - */ + *//* + @ExceptionHandler(BusinessException.class) public Response businessException(BusinessException e) { log.error(e.getMessage(), e); @@ -45,3 +49,4 @@ public class GlobalExceptionHandler{ } +*/ diff --git a/src/main/java/com/guwan/backend/face/service/FaceEngineService.java b/src/main/java/com/guwan/backend/face/service/FaceEngineService.java index b694dd0..8965414 100644 --- a/src/main/java/com/guwan/backend/face/service/FaceEngineService.java +++ b/src/main/java/com/guwan/backend/face/service/FaceEngineService.java @@ -4,9 +4,10 @@ package com.guwan.backend.face.service; import com.arcsoft.face.FaceInfo; import com.arcsoft.face.enums.ExtractType; import com.arcsoft.face.toolkit.ImageInfo; -import com.guwan.face.entity.ProcessInfo; -import com.guwan.face.entity.UserCompareInfo; -import com.guwan.face.util.UserInfo; +import com.guwan.backend.face.entity.ProcessInfo; +import com.guwan.backend.face.entity.UserCompareInfo; +import com.guwan.backend.face.util.UserInfo; + import java.util.List; diff --git a/src/main/java/com/guwan/backend/face/service/impl/FaceEngineServiceImpl.java b/src/main/java/com/guwan/backend/face/service/impl/FaceEngineServiceImpl.java index f6ef7d6..bdcb5ca 100644 --- a/src/main/java/com/guwan/backend/face/service/impl/FaceEngineServiceImpl.java +++ b/src/main/java/com/guwan/backend/face/service/impl/FaceEngineServiceImpl.java @@ -7,13 +7,14 @@ import com.arcsoft.face.enums.DetectOrient; import com.arcsoft.face.enums.ExtractType; import com.arcsoft.face.toolkit.ImageInfo; import com.google.common.collect.Lists; -import com.guwan.face.entity.ProcessInfo; -import com.guwan.face.entity.UserCompareInfo; -import com.guwan.face.enums.ErrorCodeEnum; -import com.guwan.face.factory.FaceEngineFactory; -import com.guwan.face.rpc.BusinessException; -import com.guwan.face.service.FaceEngineService; -import com.guwan.face.util.UserInfo; + +import com.guwan.backend.face.entity.ProcessInfo; +import com.guwan.backend.face.entity.UserCompareInfo; +import com.guwan.backend.face.enums.ErrorCodeEnum; +import com.guwan.backend.face.factory.FaceEngineFactory; +import com.guwan.backend.face.rpc.BusinessException; +import com.guwan.backend.face.service.FaceEngineService; +import com.guwan.backend.face.util.UserInfo; import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; import org.apache.commons.pool2.impl.GenericObjectPool; diff --git a/src/main/java/com/guwan/backend/mapper/BSCategoryMapper.java b/src/main/java/com/guwan/backend/mapper/BSCategoryMapper.java index e3f4358..7c1a122 100644 --- a/src/main/java/com/guwan/backend/mapper/BSCategoryMapper.java +++ b/src/main/java/com/guwan/backend/mapper/BSCategoryMapper.java @@ -2,6 +2,7 @@ package com.guwan.backend.mapper; import com.guwan.backend.pojo.dto.BSCategory; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; /** * @author 12455 @@ -9,6 +10,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; * @createDate 2025-03-13 23:00:51 * @Entity com.guwan.backend.pojo.dto.BSCategory */ +@Mapper public interface BSCategoryMapper extends BaseMapper { } diff --git a/src/main/java/com/guwan/backend/mapper/CoursesMapper.java b/src/main/java/com/guwan/backend/mapper/CoursesMapper.java index de97391..3a315b7 100644 --- a/src/main/java/com/guwan/backend/mapper/CoursesMapper.java +++ b/src/main/java/com/guwan/backend/mapper/CoursesMapper.java @@ -2,6 +2,7 @@ package com.guwan.backend.mapper; import com.guwan.backend.pojo.Courses; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; /** * @author 12455 @@ -9,6 +10,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; * @createDate 2025-03-13 22:45:19 * @Entity com.guwan.backend.pojo.Courses */ +@Mapper public interface CoursesMapper extends BaseMapper { } diff --git a/src/main/java/com/guwan/backend/mapper/PapersMapper.java b/src/main/java/com/guwan/backend/mapper/PapersMapper.java index ede174c..31f9954 100644 --- a/src/main/java/com/guwan/backend/mapper/PapersMapper.java +++ b/src/main/java/com/guwan/backend/mapper/PapersMapper.java @@ -2,6 +2,7 @@ package com.guwan.backend.mapper; import com.guwan.backend.pojo.entity.Papers; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; /** * @author 12455 @@ -9,6 +10,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; * @createDate 2025-01-11 12:00:45 * @Entity com.guwan.backend.pojo.entity.Papers */ +@Mapper public interface PapersMapper extends BaseMapper { } diff --git a/src/main/java/com/guwan/backend/mapper/QuestionsMapper.java b/src/main/java/com/guwan/backend/mapper/QuestionsMapper.java index d831d3a..57ae28c 100644 --- a/src/main/java/com/guwan/backend/mapper/QuestionsMapper.java +++ b/src/main/java/com/guwan/backend/mapper/QuestionsMapper.java @@ -2,6 +2,7 @@ package com.guwan.backend.mapper; import com.guwan.backend.pojo.entity.Questions; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; /** * @author 12455 @@ -9,6 +10,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; * @createDate 2025-01-11 17:53:58 * @Entity com.guwan.backend.pojo.entity.Questions */ +@Mapper public interface QuestionsMapper extends BaseMapper { } diff --git a/src/main/java/com/guwan/backend/model/exam/controller/ExamController.java b/src/main/java/com/guwan/backend/model/exam/controller/ExamController.java new file mode 100644 index 0000000..70506eb --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/controller/ExamController.java @@ -0,0 +1,70 @@ +package com.guwan.backend.model.exam.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.guwan.backend.core.api.ApiRest; +import com.guwan.backend.core.api.controller.BaseController; +import com.guwan.backend.core.api.dto.BaseIdReqDTO; +import com.guwan.backend.core.api.dto.BaseIdsReqDTO; +import com.guwan.backend.core.api.dto.BaseStateReqDTO; +import com.guwan.backend.core.api.dto.PagingReqDTO; +import com.guwan.backend.model.exam.dto.ExamDTO; +import com.guwan.backend.model.exam.dto.request.ExamSaveReqDTO; +import com.guwan.backend.model.exam.dto.response.ExamOnlineRespDTO; +import com.guwan.backend.model.exam.dto.response.ExamReviewRespDTO; +import com.guwan.backend.model.exam.entity.Exam; +import com.guwan.backend.model.exam.service.ExamService; + + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +//import org.apache.shiro.authz.annotation.RequiresRoles; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Date; + +/** +*

+* 考试控制器 +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +@Api(tags={"考试"}) +@RestController +@RequestMapping("/api/common/exam/api/exam/exam") +public class ExamController extends BaseController { + + @Autowired + private ExamService baseService; + + + /** + * 分页查找 + * @param reqDTO + * @return + */ + @ApiOperation(value = "考试视角") + @RequestMapping(value = "/online-paging", method = { RequestMethod.POST}) + public ApiRest> myPaging(@RequestBody PagingReqDTO reqDTO) { + + //分页查询并转换 + IPage page = baseService.onlinePaging(reqDTO); + return super.success(page); + } + + + @ApiOperation(value = "查找详情") + @RequestMapping(value = "/detail", method = { RequestMethod.POST}) + public ApiRest find(@RequestBody BaseIdReqDTO reqDTO) { + ExamSaveReqDTO dto = baseService.findDetail(reqDTO.getId()); + return super.success(dto); + } + + +} diff --git a/src/main/java/com/guwan/backend/model/exam/dto/ExamDTO.java b/src/main/java/com/guwan/backend/model/exam/dto/ExamDTO.java new file mode 100644 index 0000000..0d43485 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/dto/ExamDTO.java @@ -0,0 +1,103 @@ +package com.guwan.backend.model.exam.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; + + +import com.guwan.backend.model.exam.enums.ExamState; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serializable; +import java.util.Date; + +/** +*

+* 考试数据传输类 +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +@Data +@ApiModel(value="考试", description="考试") +public class ExamDTO implements Serializable { + + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "ID", required=true) + private String id; + + @ApiModelProperty(value = "考试名称", required=true) + private String title; + + @ApiModelProperty(value = "考试描述", required=true) + private String content; + + @ApiModelProperty(value = "1公开2部门3定员", required=true) + private Integer openType; + + @ApiModelProperty(value = "考试状态", required=true) + private Integer state; + + @ApiModelProperty(value = "是否限时", required=true) + private Boolean timeLimit; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + @ApiModelProperty(value = "开始时间", required=true) + private Date startTime; + + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + @ApiModelProperty(value = "结束时间", required=true) + private Date endTime; + + @ApiModelProperty(value = "创建时间", required=true) + private Date createTime; + + @ApiModelProperty(value = "更新时间", required=true) + private Date updateTime; + + @ApiModelProperty(value = "总分数", required=true) + private Integer totalScore; + + @ApiModelProperty(value = "总时长(分钟)", required=true) + private Integer totalTime; + + @ApiModelProperty(value = "及格分数", required=true) + private Integer qualifyScore; + + + + + /** + * 是否结束 + * @return + */ + public Integer getState(){ + + if(this.timeLimit!=null && this.timeLimit){ + + if(System.currentTimeMillis() < startTime.getTime() ){ + return ExamState.READY_START; + } + + if(System.currentTimeMillis() > endTime.getTime()){ + return ExamState.OVERDUE; + } + + if(System.currentTimeMillis() > startTime.getTime() + && System.currentTimeMillis() < endTime.getTime() + && !ExamState.DISABLED.equals(this.state)){ + return ExamState.ENABLE; + } + + } + + return this.state; + } +} diff --git a/src/main/java/com/guwan/backend/model/exam/dto/ExamDepartDTO.java b/src/main/java/com/guwan/backend/model/exam/dto/ExamDepartDTO.java new file mode 100644 index 0000000..85d7adc --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/dto/ExamDepartDTO.java @@ -0,0 +1,33 @@ +package com.guwan.backend.model.exam.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** +*

+* 考试部门数据传输类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-03 17:24 +*/ +@Data +@ApiModel(value="考试部门", description="考试部门") +public class ExamDepartDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "ID", required=true) + private String id; + + @ApiModelProperty(value = "考试ID", required=true) + private String examId; + + @ApiModelProperty(value = "部门ID", required=true) + private String departId; + +} diff --git a/src/main/java/com/guwan/backend/model/exam/dto/ExamRepoDTO.java b/src/main/java/com/guwan/backend/model/exam/dto/ExamRepoDTO.java new file mode 100644 index 0000000..529e839 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/dto/ExamRepoDTO.java @@ -0,0 +1,51 @@ +package com.guwan.backend.model.exam.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** +*

+* 考试题库数据传输类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-05 11:14 +*/ +@Data +@ApiModel(value="考试题库", description="考试题库") +public class ExamRepoDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "ID", required=true) + private String id; + + @ApiModelProperty(value = "考试ID", required=true) + private String examId; + + @ApiModelProperty(value = "题库ID", required=true) + private String repoId; + + @ApiModelProperty(value = "单选题数量", required=true) + private Integer radioCount; + + @ApiModelProperty(value = "单选题分数", required=true) + private Integer radioScore; + + @ApiModelProperty(value = "多选题数量", required=true) + private Integer multiCount; + + @ApiModelProperty(value = "多选题分数", required=true) + private Integer multiScore; + + @ApiModelProperty(value = "判断题数量", required=true) + private Integer judgeCount; + + @ApiModelProperty(value = "判断题分数", required=true) + private Integer judgeScore; + +} diff --git a/src/main/java/com/guwan/backend/model/exam/dto/ext/ExamRepoExtDTO.java b/src/main/java/com/guwan/backend/model/exam/dto/ext/ExamRepoExtDTO.java new file mode 100644 index 0000000..f0c2b00 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/dto/ext/ExamRepoExtDTO.java @@ -0,0 +1,33 @@ +package com.guwan.backend.model.exam.dto.ext; + + +import com.guwan.backend.model.exam.dto.ExamRepoDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** +*

+* 考试题库数据传输类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-05 11:14 +*/ +@Data +@ApiModel(value="考试题库扩展响应类", description="考试题库扩展响应类") +public class ExamRepoExtDTO extends ExamRepoDTO { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "单选题总量", required=true) + private Integer totalRadio; + + @ApiModelProperty(value = "多选题总量", required=true) + private Integer totalMulti; + + @ApiModelProperty(value = "判断题总量", required=true) + private Integer totalJudge; + +} diff --git a/src/main/java/com/guwan/backend/model/exam/dto/request/ExamSaveReqDTO.java b/src/main/java/com/guwan/backend/model/exam/dto/request/ExamSaveReqDTO.java new file mode 100644 index 0000000..08eabe9 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/dto/request/ExamSaveReqDTO.java @@ -0,0 +1,33 @@ +package com.guwan.backend.model.exam.dto.request; + + +import com.guwan.backend.model.exam.dto.ExamDTO; +import com.guwan.backend.model.exam.dto.ext.ExamRepoExtDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** +*

+* 考试保存请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +@Data +@ApiModel(value="考试保存请求类", description="考试保存请求类") +public class ExamSaveReqDTO extends ExamDTO { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "题库列表", required=true) + private List repoList; + + @ApiModelProperty(value = "考试部门列表", required=true) + private List departIds; + +} diff --git a/src/main/java/com/guwan/backend/model/exam/dto/response/ExamOnlineRespDTO.java b/src/main/java/com/guwan/backend/model/exam/dto/response/ExamOnlineRespDTO.java new file mode 100644 index 0000000..c84597a --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/dto/response/ExamOnlineRespDTO.java @@ -0,0 +1,23 @@ +package com.guwan.backend.model.exam.dto.response; + + +import com.guwan.backend.model.exam.dto.ExamDTO; +import io.swagger.annotations.ApiModel; +import lombok.Data; + +/** +*

+* 考试分页响应类 +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +@Data +@ApiModel(value="在线考试分页响应类", description="在线考试分页响应类") +public class ExamOnlineRespDTO extends ExamDTO { + + private static final long serialVersionUID = 1L; + + +} diff --git a/src/main/java/com/guwan/backend/model/exam/dto/response/ExamReviewRespDTO.java b/src/main/java/com/guwan/backend/model/exam/dto/response/ExamReviewRespDTO.java new file mode 100644 index 0000000..060c22a --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/dto/response/ExamReviewRespDTO.java @@ -0,0 +1,32 @@ +package com.guwan.backend.model.exam.dto.response; + + +import com.guwan.backend.model.exam.dto.ExamDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** +*

+* 考试分页响应类 +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +@Data +@ApiModel(value="阅卷分页响应类", description="阅卷分页响应类") +public class ExamReviewRespDTO extends ExamDTO { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "考试人数", required=true) + private Integer examUser; + + @ApiModelProperty(value = "待阅试卷", required=true) + private Integer unreadPaper; + + + +} diff --git a/src/main/java/com/guwan/backend/model/exam/entity/Exam.java b/src/main/java/com/guwan/backend/model/exam/entity/Exam.java new file mode 100644 index 0000000..0a3e0fc --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/entity/Exam.java @@ -0,0 +1,101 @@ +package com.guwan.backend.model.exam.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +import java.util.Date; + +/** +*

+* 考试实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +@Data +@TableName("el_exam") +public class Exam extends Model { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 考试名称 + */ + private String title; + + /** + * 考试描述 + */ + private String content; + + /** + * 1公开2部门3定员 + */ + @TableField("open_type") + private Integer openType; + + /** + * 考试状态 + */ + private Integer state; + + /** + * 是否限时 + */ + @TableField("time_limit") + private Boolean timeLimit; + + /** + * 开始时间 + */ + @TableField("start_time") + private Date startTime; + + /** + * 结束时间 + */ + @TableField("end_time") + private Date endTime; + + /** + * 创建时间 + */ + @TableField("create_time") + private Date createTime; + + /** + * 更新时间 + */ + @TableField("update_time") + private Date updateTime; + + /** + * 总分数 + */ + @TableField("total_score") + private Integer totalScore; + + /** + * 总时长(分钟) + */ + @TableField("total_time") + private Integer totalTime; + + /** + * 及格分数 + */ + @TableField("qualify_score") + private Integer qualifyScore; + +} diff --git a/src/main/java/com/guwan/backend/model/exam/entity/ExamDepart.java b/src/main/java/com/guwan/backend/model/exam/entity/ExamDepart.java new file mode 100644 index 0000000..5438b23 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/entity/ExamDepart.java @@ -0,0 +1,50 @@ +package com.guwan.backend.model.exam.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** +*

+* 考试部门实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-03 17:24 +*/ +@Data +@TableName("el_exam_depart") +/** + * 当你的实体类 继承 Model 后,就可以直接使用 MyBatis-Plus 提供的 Active Record (AR) 方法,例如: + * + * insert() —— 直接插入数据 + * deleteById() —— 按 ID 删除 + * selectById() —— 按 ID 查询 + * updateById() —— 按 ID 更新 + */ +public class ExamDepart extends Model { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 考试ID + */ + @TableField("exam_id") + private String examId; + + /** + * 部门ID + */ + @TableField("depart_id") + private String departId; + +} diff --git a/src/main/java/com/guwan/backend/model/exam/entity/ExamRepo.java b/src/main/java/com/guwan/backend/model/exam/entity/ExamRepo.java new file mode 100644 index 0000000..73c3411 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/entity/ExamRepo.java @@ -0,0 +1,78 @@ +package com.guwan.backend.model.exam.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** +*

+* 考试题库实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-05 11:14 +*/ +@Data +@TableName("el_exam_repo") +public class ExamRepo extends Model { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 考试ID + */ + @TableField("exam_id") + private String examId; + + /** + * 题库ID + */ + @TableField("repo_id") + private String repoId; + + /** + * 单选题数量 + */ + @TableField("radio_count") + private Integer radioCount; + + /** + * 单选题分数 + */ + @TableField("radio_score") + private Integer radioScore; + + /** + * 多选题数量 + */ + @TableField("multi_count") + private Integer multiCount; + + /** + * 多选题分数 + */ + @TableField("multi_score") + private Integer multiScore; + + /** + * 判断题数量 + */ + @TableField("judge_count") + private Integer judgeCount; + + /** + * 判断题分数 + */ + @TableField("judge_score") + private Integer judgeScore; + +} diff --git a/src/main/java/com/guwan/backend/model/exam/enums/ExamState.java b/src/main/java/com/guwan/backend/model/exam/enums/ExamState.java new file mode 100644 index 0000000..e0f460c --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/enums/ExamState.java @@ -0,0 +1,33 @@ +package com.guwan.backend.model.exam.enums; + + +/** + * 考试状态 + * @author bool + * @date 2019-10-30 13:11 + */ +public interface ExamState { + + + /** + * 考试中 + */ + Integer ENABLE = 0; + + /** + * 待阅卷 + */ + Integer DISABLED = 1; + + /** + * 已完成 + */ + Integer READY_START = 2; + + /** + * 已结束 + */ + Integer OVERDUE = 3; + + +} diff --git a/src/main/java/com/guwan/backend/model/exam/mapper/ExamDepartMapper.java b/src/main/java/com/guwan/backend/model/exam/mapper/ExamDepartMapper.java new file mode 100644 index 0000000..8b09e9c --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/mapper/ExamDepartMapper.java @@ -0,0 +1,16 @@ +package com.guwan.backend.model.exam.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.guwan.backend.model.exam.entity.ExamDepart; + +/** +*

+* 考试部门Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-09-03 17:24 +*/ +public interface ExamDepartMapper extends BaseMapper { + +} diff --git a/src/main/java/com/guwan/backend/model/exam/mapper/ExamMapper.java b/src/main/java/com/guwan/backend/model/exam/mapper/ExamMapper.java new file mode 100644 index 0000000..28a2744 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/mapper/ExamMapper.java @@ -0,0 +1,32 @@ +package com.guwan.backend.model.exam.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; + +import com.guwan.backend.model.exam.dto.ExamDTO; +import com.guwan.backend.model.exam.dto.response.ExamOnlineRespDTO; +import com.guwan.backend.model.exam.dto.response.ExamReviewRespDTO; +import com.guwan.backend.model.exam.entity.Exam; +import org.apache.ibatis.annotations.Param; + +/** +*

+* 考试Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +public interface ExamMapper extends BaseMapper { + + + + /** + * 在线考试分页响应类-考生视角 + * @param page + * @param query + * @return + */ + IPage online(Page page, @Param("query") ExamDTO query); +} diff --git a/src/main/java/com/guwan/backend/model/exam/mapper/ExamRepoMapper.java b/src/main/java/com/guwan/backend/model/exam/mapper/ExamRepoMapper.java new file mode 100644 index 0000000..e20dc08 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/mapper/ExamRepoMapper.java @@ -0,0 +1,27 @@ +package com.guwan.backend.model.exam.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +import com.guwan.backend.model.exam.dto.ext.ExamRepoExtDTO; +import com.guwan.backend.model.exam.entity.ExamRepo; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** +*

+* 考试题库Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-09-05 11:14 +*/ +public interface ExamRepoMapper extends BaseMapper { + + /** + * 查找考试题库列表 + * @param examId + * @return + */ + List listByExam(@Param("examId") String examId); +} diff --git a/src/main/java/com/guwan/backend/model/exam/service/ExamDepartService.java b/src/main/java/com/guwan/backend/model/exam/service/ExamDepartService.java new file mode 100644 index 0000000..5645ff7 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/service/ExamDepartService.java @@ -0,0 +1,26 @@ +package com.guwan.backend.model.exam.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.guwan.backend.model.exam.entity.ExamDepart; + + +import java.util.List; + +/** +*

+* 考试部门业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-03 17:24 +*/ +public interface ExamDepartService extends IService { + + + /** + * 根据考试查找对应的部门 + * @param examId + * @return + */ + List listByExam(String examId); +} diff --git a/src/main/java/com/guwan/backend/model/exam/service/ExamRepoService.java b/src/main/java/com/guwan/backend/model/exam/service/ExamRepoService.java new file mode 100644 index 0000000..1505798 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/service/ExamRepoService.java @@ -0,0 +1,30 @@ +package com.guwan.backend.model.exam.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.guwan.backend.model.exam.dto.ext.ExamRepoExtDTO; +import com.guwan.backend.model.exam.entity.ExamRepo; + + + +import java.util.List; + +/** +*

+* 考试题库业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-05 11:14 +*/ +public interface ExamRepoService extends IService { + + /** + * 查找考试题库列表 + * @param examId + * @return + */ + List listByExam(String examId); + + + +} diff --git a/src/main/java/com/guwan/backend/model/exam/service/ExamService.java b/src/main/java/com/guwan/backend/model/exam/service/ExamService.java new file mode 100644 index 0000000..4787383 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/service/ExamService.java @@ -0,0 +1,34 @@ +package com.guwan.backend.model.exam.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.guwan.backend.core.api.dto.PagingReqDTO; +import com.guwan.backend.model.exam.dto.ExamDTO; +import com.guwan.backend.model.exam.dto.request.ExamSaveReqDTO; +import com.guwan.backend.model.exam.dto.response.ExamOnlineRespDTO; +import com.guwan.backend.model.exam.dto.response.ExamReviewRespDTO; +import com.guwan.backend.model.exam.entity.Exam; + + +/** +*

+* 考试业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +public interface ExamService extends IService { + + + + /** + * 在线考试分页响应类-考生视角 + * @param reqDTO + * @return + */ + IPage onlinePaging(PagingReqDTO reqDTO); + + ExamSaveReqDTO findDetail(String id); + +} diff --git a/src/main/java/com/guwan/backend/model/exam/service/impl/ExamDepartServiceImpl.java b/src/main/java/com/guwan/backend/model/exam/service/impl/ExamDepartServiceImpl.java new file mode 100644 index 0000000..c93a83d --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/service/impl/ExamDepartServiceImpl.java @@ -0,0 +1,45 @@ +package com.guwan.backend.model.exam.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; + + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.guwan.backend.model.exam.entity.ExamDepart; +import com.guwan.backend.model.exam.mapper.ExamDepartMapper; +import com.guwan.backend.model.exam.service.ExamDepartService; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; + +/** +*

+* 考试部门业务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-03 17:24 +*/ +@Service +public class ExamDepartServiceImpl extends ServiceImpl implements ExamDepartService { + + + + @Override + public List listByExam(String examId) { + // 先删除 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(ExamDepart::getExamId, examId); + List list = this.list(wrapper); + List ids = new ArrayList<>(); + if(!CollectionUtils.isEmpty(list)){ + for(ExamDepart item: list){ + ids.add(item.getDepartId()); + } + } + + return ids; + + } +} diff --git a/src/main/java/com/guwan/backend/model/exam/service/impl/ExamRepoServiceImpl.java b/src/main/java/com/guwan/backend/model/exam/service/impl/ExamRepoServiceImpl.java new file mode 100644 index 0000000..765e92e --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/service/impl/ExamRepoServiceImpl.java @@ -0,0 +1,39 @@ +package com.guwan.backend.model.exam.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import com.guwan.backend.model.exam.dto.ext.ExamRepoExtDTO; +import com.guwan.backend.model.exam.entity.ExamRepo; +import com.guwan.backend.model.exam.mapper.ExamRepoMapper; +import com.guwan.backend.model.exam.service.ExamRepoService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.util.List; + +/** +*

+* 考试题库业务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-05 11:14 +*/ +@Service +public class ExamRepoServiceImpl extends ServiceImpl implements ExamRepoService { + + + + + @Override + public List listByExam(String examId) { + return baseMapper.listByExam(examId); + } + + + + +} diff --git a/src/main/java/com/guwan/backend/model/exam/service/impl/ExamServiceImpl.java b/src/main/java/com/guwan/backend/model/exam/service/impl/ExamServiceImpl.java new file mode 100644 index 0000000..7cf009c --- /dev/null +++ b/src/main/java/com/guwan/backend/model/exam/service/impl/ExamServiceImpl.java @@ -0,0 +1,77 @@ +package com.guwan.backend.model.exam.service.impl; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import com.guwan.backend.core.api.dto.PagingReqDTO; + +import com.guwan.backend.core.BeanMapper; +import com.guwan.backend.model.exam.dto.ExamDTO; +import com.guwan.backend.model.exam.dto.ext.ExamRepoExtDTO; +import com.guwan.backend.model.exam.dto.request.ExamSaveReqDTO; +import com.guwan.backend.model.exam.dto.response.ExamOnlineRespDTO; +import com.guwan.backend.model.exam.entity.Exam; +import com.guwan.backend.model.exam.mapper.ExamMapper; +import com.guwan.backend.model.exam.service.ExamDepartService; +import com.guwan.backend.model.exam.service.ExamRepoService; +import com.guwan.backend.model.exam.service.ExamService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** +*

+* 考试业务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +@Service +public class ExamServiceImpl extends ServiceImpl implements ExamService { + + + @Autowired + private ExamRepoService examRepoService; + + @Autowired + private ExamDepartService examDepartService; + + + + + + @Override + public IPage onlinePaging(PagingReqDTO reqDTO) { + + + // 创建分页对象 + Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); + + // 查找分页 + IPage pageData = baseMapper.online(page, reqDTO.getParams()); + + return pageData; + } + + @Override + public ExamSaveReqDTO findDetail(String id) { + ExamSaveReqDTO respDTO = new ExamSaveReqDTO(); + Exam exam = this.getById(id); + BeanMapper.copy(exam, respDTO); + + // 考试部门 + List departIds = examDepartService.listByExam(id); + respDTO.setDepartIds(departIds); + + // 题库 + List repos = examRepoService.listByExam(id); + respDTO.setRepoList(repos); + + return respDTO; + } + + +} diff --git a/src/main/java/com/guwan/backend/model/paper/controller/PaperController.java b/src/main/java/com/guwan/backend/model/paper/controller/PaperController.java new file mode 100644 index 0000000..dcd07f4 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/controller/PaperController.java @@ -0,0 +1,171 @@ +package com.guwan.backend.model.paper.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; + +import com.guwan.backend.core.api.ApiRest; +import com.guwan.backend.core.api.controller.BaseController; +import com.guwan.backend.core.api.dto.BaseIdReqDTO; +import com.guwan.backend.core.api.dto.BaseIdRespDTO; +import com.guwan.backend.core.api.dto.PagingReqDTO; +import com.guwan.backend.model.paper.dto.PaperDTO; +import com.guwan.backend.model.paper.dto.ext.PaperQuDetailDTO; +import com.guwan.backend.model.paper.dto.request.PaperAnswerDTO; +import com.guwan.backend.model.paper.dto.request.PaperCreateReqDTO; +import com.guwan.backend.model.paper.dto.request.PaperListReqDTO; +import com.guwan.backend.model.paper.dto.request.PaperQuQueryDTO; +import com.guwan.backend.model.paper.dto.response.ExamDetailRespDTO; +import com.guwan.backend.model.paper.dto.response.ExamResultRespDTO; +import com.guwan.backend.model.paper.dto.response.PaperListRespDTO; +import com.guwan.backend.model.paper.service.PaperService; +import com.guwan.backend.model.user.UserUtils; +import com.guwan.backend.security.CustomUserDetails; +import com.guwan.backend.util.JwtUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** +*

+* 试卷控制器 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 16:33 +*/ +@Api(tags={"试卷"}) +@RestController +@RequestMapping("/exam/api/paper/paper") +public class PaperController extends BaseController { + + @Autowired + private PaperService baseService; + + @Autowired + private JwtUtil jwtUtil; + + /** + * 分页查找 + * @param reqDTO + * @return + */ + @ApiOperation(value = "分页查找") + @RequestMapping(value = "/paging", method = { RequestMethod.POST}) + public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { + //分页查询并转换 + IPage page = baseService.paging(reqDTO); + return super.success(page); + } + + + + /** + * 创建试卷 + * @param reqDTO + * @return + */ + @ApiOperation(value = "创建试卷") + @RequestMapping(value = "/create-paper", method = { RequestMethod.POST}) + public ApiRest save(@RequestBody PaperCreateReqDTO reqDTO) { + + + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null && authentication.getPrincipal() instanceof CustomUserDetails userDetails) { + // sysLog.setUserId(userDetails.getUserId()); + // sysLog.setUsername(userDetails.getUsername()); + } + + + //复制参数 + // String paperId = baseService.createPaper(UserUtils.getUserId(), reqDTO.getExamId()); + String paperId = baseService.createPaper(jwtUtil.getUserIdFromToken("111") + "", + reqDTO.getExamId()); + + return super.success(new BaseIdRespDTO(paperId)); + } + + /** + * 批量删除 + * @param reqDTO + * @return + */ + @ApiOperation(value = "试卷详情") + @RequestMapping(value = "/paper-detail", method = { RequestMethod.POST}) + public ApiRest paperDetail(@RequestBody BaseIdReqDTO reqDTO) { + //根据ID删除 + ExamDetailRespDTO respDTO = baseService.paperDetail(reqDTO.getId()); + return super.success(respDTO); + } + + /** + * 批量删除 + * @param reqDTO + * @return + */ + @ApiOperation(value = "试题详情") + @RequestMapping(value = "/qu-detail", method = { RequestMethod.POST}) + public ApiRest quDetail(@RequestBody PaperQuQueryDTO reqDTO) { + //根据ID删除 + PaperQuDetailDTO respDTO = baseService.findQuDetail(reqDTO.getPaperId(), reqDTO.getQuId()); + return super.success(respDTO); + } + + /** + * 填充答案 + * @param reqDTO + * @return + */ + @ApiOperation(value = "填充答案") + @RequestMapping(value = "/fill-answer", method = { RequestMethod.POST}) + public ApiRest fillAnswer(@RequestBody PaperAnswerDTO reqDTO) { + //根据ID删除 + baseService.fillAnswer(reqDTO); + return super.success(); + } + + + /** + * 交卷操作 + * @param reqDTO + * @return + */ + @ApiOperation(value = "交卷操作") + @RequestMapping(value = "/hand-exam", method = { RequestMethod.POST}) + public ApiRest handleExam(@RequestBody BaseIdReqDTO reqDTO) { + //根据ID删除 + baseService.handExam(reqDTO.getId()); + return super.success(); + } + + + /** + * 批量删除 + * @param reqDTO + * @return + */ + @ApiOperation(value = "试卷详情") + @RequestMapping(value = "/paper-result", method = { RequestMethod.POST}) + public ApiRest paperResult(@RequestBody BaseIdReqDTO reqDTO) { + //根据ID删除 + ExamResultRespDTO respDTO = baseService.paperResult(reqDTO.getId()); + return super.success(respDTO); + } + + + /** + * 检测用户有没有中断的考试 + * @return + */ + @ApiOperation(value = "检测进行中的考试") + @RequestMapping(value = "/check-process", method = { RequestMethod.POST}) + public ApiRest checkProcess() { + //复制参数 + PaperDTO dto = baseService.checkProcess(UserUtils.getUserId()); + return super.success(dto); + } +} diff --git a/src/main/java/com/guwan/backend/model/paper/dto/PaperDTO.java b/src/main/java/com/guwan/backend/model/paper/dto/PaperDTO.java new file mode 100644 index 0000000..62ebd7d --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/dto/PaperDTO.java @@ -0,0 +1,80 @@ +package com.guwan.backend.model.paper.dto; + + +import com.guwan.backend.core.annon.Dict; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** +*

+* 试卷请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@ApiModel(value="试卷", description="试卷") +public class PaperDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "试卷ID", required=true) + private String id; + + @Dict(dictTable = "sys_user", dicText = "real_name", dicCode = "id") + @ApiModelProperty(value = "用户ID", required=true) + private String userId; + + @Dict(dictTable = "sys_depart", dicText = "dept_name", dicCode = "id") + @ApiModelProperty(value = "部门ID", required=true) + private String departId; + + @ApiModelProperty(value = "规则ID", required=true) + private String examId; + + @ApiModelProperty(value = "考试标题", required=true) + private String title; + + @ApiModelProperty(value = "考试时长", required=true) + private Integer totalTime; + + @ApiModelProperty(value = "用户时长", required=true) + private Integer userTime; + + @ApiModelProperty(value = "试卷总分", required=true) + private Integer totalScore; + + @ApiModelProperty(value = "及格分", required=true) + private Integer qualifyScore; + + @ApiModelProperty(value = "客观分", required=true) + private Integer objScore; + + @ApiModelProperty(value = "主观分", required=true) + private Integer subjScore; + + @ApiModelProperty(value = "用户得分", required=true) + private Integer userScore; + + @ApiModelProperty(value = "是否包含简答题", required=true) + private Boolean hasSaq; + + @ApiModelProperty(value = "试卷状态", required=true) + private Integer state; + + @ApiModelProperty(value = "创建时间", required=true) + private Date createTime; + + @ApiModelProperty(value = "更新时间", required=true) + private Date updateTime; + + @ApiModelProperty(value = "截止时间") + private Date limitTime; + +} diff --git a/src/main/java/com/guwan/backend/model/paper/dto/PaperQuAnswerDTO.java b/src/main/java/com/guwan/backend/model/paper/dto/PaperQuAnswerDTO.java new file mode 100644 index 0000000..24a0340 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/dto/PaperQuAnswerDTO.java @@ -0,0 +1,48 @@ +package com.guwan.backend.model.paper.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** +*

+* 试卷考题备选答案请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@ApiModel(value="试卷考题备选答案", description="试卷考题备选答案") +public class PaperQuAnswerDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "自增ID", required=true) + private String id; + + @ApiModelProperty(value = "试卷ID", required=true) + private String paperId; + + @ApiModelProperty(value = "回答项ID", required=true) + private String answerId; + + @ApiModelProperty(value = "题目ID", required=true) + private String quId; + + @ApiModelProperty(value = "是否正确项", required=true) + private Boolean isRight; + + @ApiModelProperty(value = "是否选中", required=true) + private Boolean checked; + + @ApiModelProperty(value = "排序", required=true) + private Integer sort; + + @ApiModelProperty(value = "选项标签", required=true) + private String abc; + +} diff --git a/src/main/java/com/guwan/backend/model/paper/dto/PaperQuDTO.java b/src/main/java/com/guwan/backend/model/paper/dto/PaperQuDTO.java new file mode 100644 index 0000000..993855c --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/dto/PaperQuDTO.java @@ -0,0 +1,54 @@ +package com.guwan.backend.model.paper.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** +*

+* 试卷考题请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@ApiModel(value="试卷考题", description="试卷考题") +public class PaperQuDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "ID", required=true) + private String id; + + @ApiModelProperty(value = "试卷ID", required=true) + private String paperId; + + @ApiModelProperty(value = "题目ID", required=true) + private String quId; + + @ApiModelProperty(value = "题目类型", required=true) + private Integer quType; + + @ApiModelProperty(value = "是否已答", required=true) + private Boolean answered; + + @ApiModelProperty(value = "主观答案", required=true) + private String answer; + + @ApiModelProperty(value = "问题排序", required=true) + private Integer sort; + + @ApiModelProperty(value = "单题分分值", required=true) + private Integer score; + + @ApiModelProperty(value = "实际得分(主观题)", required=true) + private Integer actualScore; + + @ApiModelProperty(value = "是否答对", required=true) + private Boolean isRight; + +} diff --git a/src/main/java/com/guwan/backend/model/paper/dto/ext/PaperQuAnswerExtDTO.java b/src/main/java/com/guwan/backend/model/paper/dto/ext/PaperQuAnswerExtDTO.java new file mode 100644 index 0000000..f283b40 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/dto/ext/PaperQuAnswerExtDTO.java @@ -0,0 +1,29 @@ +package com.guwan.backend.model.paper.dto.ext; + + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** +*

+* 试卷考题备选答案请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@ApiModel(value="试卷考题备选答案", description="试卷考题备选答案") +public class PaperQuAnswerExtDTO extends PaperQuAnswerDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "试题图片", required=true) + private String image; + + @ApiModelProperty(value = "答案内容", required=true) + private String content; + + +} diff --git a/src/main/java/com/guwan/backend/model/paper/dto/ext/PaperQuDetailDTO.java b/src/main/java/com/guwan/backend/model/paper/dto/ext/PaperQuDetailDTO.java new file mode 100644 index 0000000..2d8c854 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/dto/ext/PaperQuDetailDTO.java @@ -0,0 +1,33 @@ +package com.guwan.backend.model.paper.dto.ext; + + +import com.guwan.backend.model.paper.dto.PaperQuDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** +*

+* 试卷考题请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@ApiModel(value="试卷题目详情类", description="试卷题目详情类") +public class PaperQuDetailDTO extends PaperQuDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "图片", required=true) + private String image; + + @ApiModelProperty(value = "题目内容", required=true) + private String content; + + @ApiModelProperty(value = "答案内容", required=true) + List answerList; +} diff --git a/src/main/java/com/guwan/backend/model/paper/dto/request/PaperAnswerDTO.java b/src/main/java/com/guwan/backend/model/paper/dto/request/PaperAnswerDTO.java new file mode 100644 index 0000000..01f9f97 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/dto/request/PaperAnswerDTO.java @@ -0,0 +1,22 @@ +package com.guwan.backend.model.paper.dto.request; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * @author bool + */ +@Data +@ApiModel(value="查找试卷题目详情请求类", description="查找试卷题目详情请求类") +public class PaperAnswerDTO extends PaperQuQueryDTO { + + @ApiModelProperty(value = "回答列表", required=true) + private List answers; + + @ApiModelProperty(value = "主观答案", required=true) + private String answer; + +} diff --git a/src/main/java/com/guwan/backend/model/paper/dto/request/PaperCreateReqDTO.java b/src/main/java/com/guwan/backend/model/paper/dto/request/PaperCreateReqDTO.java new file mode 100644 index 0000000..b54ab9d --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/dto/request/PaperCreateReqDTO.java @@ -0,0 +1,22 @@ +package com.guwan.backend.model.paper.dto.request; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.yf.exam.core.api.dto.BaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author bool + */ +@Data +@ApiModel(value="试卷创建请求类", description="试卷创建请求类") +public class PaperCreateReqDTO extends BaseDTO { + + @JsonIgnore + private String userId; + + @ApiModelProperty(value = "考试ID", required=true) + private String examId; + +} diff --git a/src/main/java/com/guwan/backend/model/paper/dto/request/PaperListReqDTO.java b/src/main/java/com/guwan/backend/model/paper/dto/request/PaperListReqDTO.java new file mode 100644 index 0000000..f2544c7 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/dto/request/PaperListReqDTO.java @@ -0,0 +1,39 @@ +package com.guwan.backend.model.paper.dto.request; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** +*

+* 试卷请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@ApiModel(value="试卷", description="试卷") +public class PaperListReqDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "用户ID", required=true) + private String userId; + + @ApiModelProperty(value = "部门ID", required=true) + private String departId; + + @ApiModelProperty(value = "规则ID", required=true) + private String examId; + + @ApiModelProperty(value = "用户昵称", required=true) + private String realName; + + @ApiModelProperty(value = "试卷状态", required=true) + private Integer state; + + +} diff --git a/src/main/java/com/guwan/backend/model/paper/dto/request/PaperQuQueryDTO.java b/src/main/java/com/guwan/backend/model/paper/dto/request/PaperQuQueryDTO.java new file mode 100644 index 0000000..8d72e18 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/dto/request/PaperQuQueryDTO.java @@ -0,0 +1,21 @@ +package com.guwan.backend.model.paper.dto.request; + +import com.yf.exam.core.api.dto.BaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author bool + */ +@Data +@ApiModel(value="查找试卷题目详情请求类", description="查找试卷题目详情请求类") +public class PaperQuQueryDTO extends BaseDTO { + + @ApiModelProperty(value = "试卷ID", required=true) + private String paperId; + + @ApiModelProperty(value = "题目ID", required=true) + private String quId; + +} diff --git a/src/main/java/com/guwan/backend/model/paper/dto/response/ExamDetailRespDTO.java b/src/main/java/com/guwan/backend/model/paper/dto/response/ExamDetailRespDTO.java new file mode 100644 index 0000000..f9171f8 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/dto/response/ExamDetailRespDTO.java @@ -0,0 +1,39 @@ +package com.guwan.backend.model.paper.dto.response; + + +import com.guwan.backend.model.paper.dto.PaperDTO; +import com.guwan.backend.model.paper.dto.PaperQuDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Calendar; +import java.util.List; + +@Data +@ApiModel(value="考试详情", description="考试详情") +public class ExamDetailRespDTO extends PaperDTO { + + + @ApiModelProperty(value = "单选题列表", required=true) + private List radioList; + + @ApiModelProperty(value = "多选题列表", required=true) + private List multiList; + + @ApiModelProperty(value = "判断题", required=true) + private List judgeList; + + + @ApiModelProperty(value = "剩余结束秒数", required=true) + public Long getLeftSeconds(){ + + // 结束时间 + Calendar cl = Calendar.getInstance(); + cl.setTime(this.getCreateTime()); + cl.add(Calendar.MINUTE, getTotalTime()); + + return (cl.getTimeInMillis() - System.currentTimeMillis()) / 1000; + } + +} diff --git a/src/main/java/com/guwan/backend/model/paper/dto/response/ExamResultRespDTO.java b/src/main/java/com/guwan/backend/model/paper/dto/response/ExamResultRespDTO.java new file mode 100644 index 0000000..f715cdd --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/dto/response/ExamResultRespDTO.java @@ -0,0 +1,19 @@ +package com.guwan.backend.model.paper.dto.response; + + +import com.guwan.backend.model.paper.dto.PaperDTO; +import com.guwan.backend.model.paper.dto.ext.PaperQuDetailDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +@ApiModel(value="考试结果展示响应类", description="考试结果展示响应类") +public class ExamResultRespDTO extends PaperDTO { + + @ApiModelProperty(value = "问题列表", required=true) + private List quList; + +} diff --git a/src/main/java/com/guwan/backend/model/paper/dto/response/PaperListRespDTO.java b/src/main/java/com/guwan/backend/model/paper/dto/response/PaperListRespDTO.java new file mode 100644 index 0000000..b163a2c --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/dto/response/PaperListRespDTO.java @@ -0,0 +1,27 @@ +package com.guwan.backend.model.paper.dto.response; + + +import com.guwan.backend.model.paper.dto.PaperDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** +*

+* 试卷请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@ApiModel(value="试卷列表响应类", description="试卷列表响应类") +public class PaperListRespDTO extends PaperDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "人员", required=true) + private String realName; + + +} diff --git a/src/main/java/com/guwan/backend/model/paper/entity/Paper.java b/src/main/java/com/guwan/backend/model/paper/entity/Paper.java new file mode 100644 index 0000000..9839bd2 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/entity/Paper.java @@ -0,0 +1,125 @@ +package com.guwan.backend.model.paper.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +import java.util.Date; + +/** +*

+* 试卷实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@TableName("el_paper") +public class Paper extends Model { + + private static final long serialVersionUID = 1L; + + /** + * 试卷ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 用户ID + */ + @TableField("user_id") + private String userId; + + /** + * 部门ID + */ + @TableField("depart_id") + private String departId; + + /** + * 规则ID + */ + @TableField("exam_id") + private String examId; + + /** + * 考试标题 + */ + private String title; + + /** + * 考试时长 + */ + @TableField("total_time") + private Integer totalTime; + + /** + * 用户时长 + */ + @TableField("user_time") + private Integer userTime; + + /** + * 试卷总分 + */ + @TableField("total_score") + private Integer totalScore; + + /** + * 及格分 + */ + @TableField("qualify_score") + private Integer qualifyScore; + + /** + * 客观分 + */ + @TableField("obj_score") + private Integer objScore; + + /** + * 主观分 + */ + @TableField("subj_score") + private Integer subjScore; + + /** + * 用户得分 + */ + @TableField("user_score") + private Integer userScore; + + /** + * 是否包含简答题 + */ + @TableField("has_saq") + private Boolean hasSaq; + + /** + * 试卷状态 + */ + private Integer state; + + /** + * 创建时间 + */ + @TableField("create_time") + private Date createTime; + + /** + * 更新时间 + */ + @TableField("update_time") + private Date updateTime; + + /** + * 截止时间 + */ + @TableField("limit_time") + private Date limitTime; +} diff --git a/src/main/java/com/guwan/backend/model/paper/entity/PaperQu.java b/src/main/java/com/guwan/backend/model/paper/entity/PaperQu.java new file mode 100644 index 0000000..b89799d --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/entity/PaperQu.java @@ -0,0 +1,80 @@ +package com.guwan.backend.model.paper.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** +*

+* 试卷考题实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@TableName("el_paper_qu") +public class PaperQu extends Model { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 试卷ID + */ + @TableField("paper_id") + private String paperId; + + /** + * 题目ID + */ + @TableField("qu_id") + private String quId; + + /** + * 题目类型 + */ + @TableField("qu_type") + private Integer quType; + + /** + * 是否已答 + */ + private Boolean answered; + + /** + * 主观答案 + */ + private String answer; + + /** + * 问题排序 + */ + private Integer sort; + + /** + * 单题分分值 + */ + private Integer score; + + /** + * 实际得分(主观题) + */ + @TableField("actual_score") + private Integer actualScore; + + /** + * 是否答对 + */ + @TableField("is_right") + private Boolean isRight; + +} diff --git a/src/main/java/com/guwan/backend/model/paper/entity/PaperQuAnswer.java b/src/main/java/com/guwan/backend/model/paper/entity/PaperQuAnswer.java new file mode 100644 index 0000000..7fc66d3 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/entity/PaperQuAnswer.java @@ -0,0 +1,68 @@ +package com.guwan.backend.model.paper.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** +*

+* 试卷考题备选答案实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@TableName("el_paper_qu_answer") +public class PaperQuAnswer extends Model { + + + /** + * 自增ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 试卷ID + */ + @TableField("paper_id") + private String paperId; + + /** + * 回答项ID + */ + @TableField("answer_id") + private String answerId; + + /** + * 题目ID + */ + @TableField("qu_id") + private String quId; + + /** + * 是否正确项 + */ + @TableField("is_right") + private Boolean isRight; + + /** + * 是否选中 + */ + private Boolean checked; + + /** + * 排序 + */ + private Integer sort; + + /** + * 选项标签 + */ + private String abc; + +} diff --git a/src/main/java/com/guwan/backend/model/paper/enums/ExamState.java b/src/main/java/com/guwan/backend/model/paper/enums/ExamState.java new file mode 100644 index 0000000..50f31d7 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/enums/ExamState.java @@ -0,0 +1,33 @@ +package com.guwan.backend.model.paper.enums; + + +/** + * 考试状态 + * @author bool + * @date 2019-10-30 13:11 + */ +public interface ExamState { + + + /** + * 考试中 + */ + Integer ENABLE = 0; + + /** + * 待阅卷 + */ + Integer DISABLED = 1; + + /** + * 已完成 + */ + Integer READY_START = 2; + + /** + * 已结束 + */ + Integer OVERDUE = 3; + + +} diff --git a/src/main/java/com/guwan/backend/model/paper/enums/PaperState.java b/src/main/java/com/guwan/backend/model/paper/enums/PaperState.java new file mode 100644 index 0000000..08c0295 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/enums/PaperState.java @@ -0,0 +1,33 @@ +package com.guwan.backend.model.paper.enums; + + +/** + * 试卷状态 + * @author bool + * @date 2019-10-30 13:11 + */ +public interface PaperState { + + + /** + * 考试中 + */ + Integer ING = 0; + + /** + * 待阅卷 + */ + Integer WAIT_OPT = 1; + + /** + * 已完成 + */ + Integer FINISHED = 2; + + /** + * 弃考 + */ + Integer BREAK = 3; + + +} diff --git a/src/main/java/com/guwan/backend/model/paper/job/BreakExamJob.java b/src/main/java/com/guwan/backend/model/paper/job/BreakExamJob.java new file mode 100644 index 0000000..fad9698 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/job/BreakExamJob.java @@ -0,0 +1,45 @@ +package com.guwan.backend.model.paper.job; + +import com.yf.exam.ability.job.service.JobService; +import com.yf.exam.modules.paper.service.PaperService; +import lombok.extern.log4j.Log4j2; +import org.quartz.Job; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 超时自动交卷任务 + * @author bool + */ +@Log4j2 +@Component +public class BreakExamJob implements Job { + + @Autowired + private PaperService paperService; + + @Override + public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + + JobDetail detail = jobExecutionContext.getJobDetail(); + String name = detail.getKey().getName(); + String group = detail.getKey().getGroup(); + String data = String.valueOf(detail.getJobDataMap().get(JobService.TASK_DATA)); + + log.info("++++++++++定时任务:处理到期的交卷"); + log.info("++++++++++jobName:{}", name); + log.info("++++++++++jobGroup:{}", group); + log.info("++++++++++taskData:{}", data); + + + // 强制交卷 + paperService.handExam(data); + + } + + + +} diff --git a/src/main/java/com/guwan/backend/model/paper/mapper/PaperMapper.java b/src/main/java/com/guwan/backend/model/paper/mapper/PaperMapper.java new file mode 100644 index 0000000..cf9537e --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/mapper/PaperMapper.java @@ -0,0 +1,40 @@ +package com.guwan.backend.model.paper.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; + +import com.guwan.backend.model.paper.dto.PaperDTO; +import com.guwan.backend.model.paper.dto.request.PaperListReqDTO; +import com.guwan.backend.model.paper.dto.response.PaperListRespDTO; +import com.guwan.backend.model.paper.entity.Paper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** +*

+* 试卷Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 16:33 +*/ +public interface PaperMapper extends BaseMapper { + + /** + * 查找试卷分页 + * @param page + * @param query + * @return + */ + IPage paging(Page page, @Param("query") PaperListReqDTO query); + + + /** + * 试卷列表响应类 + * @param query + * @return + */ + List list(@Param("query") PaperDTO query); +} diff --git a/src/main/java/com/guwan/backend/model/paper/mapper/PaperQuAnswerMapper.java b/src/main/java/com/guwan/backend/model/paper/mapper/PaperQuAnswerMapper.java new file mode 100644 index 0000000..abefa48 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/mapper/PaperQuAnswerMapper.java @@ -0,0 +1,27 @@ +package com.guwan.backend.model.paper.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.guwan.backend.model.paper.dto.ext.PaperQuAnswerExtDTO; +import com.guwan.backend.model.paper.entity.PaperQuAnswer; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** +*

+* 试卷考题备选答案Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 16:33 +*/ +public interface PaperQuAnswerMapper extends BaseMapper { + + /** + * 查找试卷试题答案列表 + * @param paperId + * @param quId + * @return + */ + List list(@Param("paperId") String paperId, @Param("quId") String quId); +} diff --git a/src/main/java/com/guwan/backend/model/paper/mapper/PaperQuMapper.java b/src/main/java/com/guwan/backend/model/paper/mapper/PaperQuMapper.java new file mode 100644 index 0000000..c8b183a --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/mapper/PaperQuMapper.java @@ -0,0 +1,42 @@ +package com.guwan.backend.model.paper.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.guwan.backend.model.paper.dto.ext.PaperQuDetailDTO; +import com.guwan.backend.model.paper.entity.PaperQu; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** +*

+* 试卷考题Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 16:33 +*/ +public interface PaperQuMapper extends BaseMapper { + + /** + * 统计客观分 + * @param paperId + * @return + */ + int sumObjective(@Param("paperId") String paperId); + + /** + * 统计主观分 + * @param paperId + * @return + */ + int sumSubjective(@Param("paperId") String paperId); + + /** + * 找出全部试题列表 + * @param paperId + * @return + */ + List listByPaper(@Param("paperId") String paperId); +} + + diff --git a/src/main/java/com/guwan/backend/model/paper/service/PaperQuAnswerService.java b/src/main/java/com/guwan/backend/model/paper/service/PaperQuAnswerService.java new file mode 100644 index 0000000..d9f00f6 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/service/PaperQuAnswerService.java @@ -0,0 +1,45 @@ +package com.guwan.backend.model.paper.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.guwan.backend.core.api.dto.PagingReqDTO; +import com.guwan.backend.model.paper.dto.PaperQuAnswerDTO; +import com.guwan.backend.model.paper.dto.ext.PaperQuAnswerExtDTO; +import com.guwan.backend.model.paper.entity.PaperQuAnswer; + + +import java.util.List; + +/** +*

+* 试卷考题备选答案业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 16:33 +*/ +public interface PaperQuAnswerService extends IService { + + /** + * 分页查询数据 + * @param reqDTO + * @return + */ + IPage paging(PagingReqDTO reqDTO); + + /** + * 查找试卷试题答案列表 + * @param paperId + * @param quId + * @return + */ + List listForExam(String paperId, String quId); + + /** + * 查找答案列表,用来填充 + * @param paperId + * @param quId + * @return + */ + List listForFill(String paperId, String quId); +} diff --git a/src/main/java/com/guwan/backend/model/paper/service/PaperQuService.java b/src/main/java/com/guwan/backend/model/paper/service/PaperQuService.java new file mode 100644 index 0000000..4bc3097 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/service/PaperQuService.java @@ -0,0 +1,71 @@ +package com.guwan.backend.model.paper.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.guwan.backend.core.api.dto.PagingReqDTO; +import com.guwan.backend.model.paper.dto.PaperQuDTO; +import com.guwan.backend.model.paper.dto.ext.PaperQuDetailDTO; +import com.guwan.backend.model.paper.entity.PaperQu; + + +import java.util.List; + +/** +*

+* 试卷考题业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 16:33 +*/ +public interface PaperQuService extends IService { + + /** + * 分页查询数据 + * @param reqDTO + * @return + */ + IPage paging(PagingReqDTO reqDTO); + + /** + * 根据试卷找出题目列表 + * @param paperId + * @return + */ + List listByPaper(String paperId); + + /** + * 查找详情 + * @param paperId + * @param quId + * @return + */ + PaperQu findByKey(String paperId, String quId); + + /** + * 根据组合索引更新 + * @param qu + */ + void updateByKey(PaperQu qu); + + /** + * 统计客观分 + * @param paperId + * @return + */ + int sumObjective(String paperId); + + /** + * 统计主观分 + * @param paperId + * @return + */ + int sumSubjective(String paperId); + + /** + * 找出全部试题列表 + * @param paperId + * @return + */ + List listForPaperResult(String paperId); +} diff --git a/src/main/java/com/guwan/backend/model/paper/service/PaperService.java b/src/main/java/com/guwan/backend/model/paper/service/PaperService.java new file mode 100644 index 0000000..047c91d --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/service/PaperService.java @@ -0,0 +1,84 @@ +package com.guwan.backend.model.paper.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.guwan.backend.core.api.dto.PagingReqDTO; +import com.guwan.backend.model.paper.dto.PaperDTO; +import com.guwan.backend.model.paper.dto.ext.PaperQuDetailDTO; +import com.guwan.backend.model.paper.dto.request.PaperAnswerDTO; +import com.guwan.backend.model.paper.dto.request.PaperListReqDTO; +import com.guwan.backend.model.paper.dto.response.ExamDetailRespDTO; +import com.guwan.backend.model.paper.dto.response.ExamResultRespDTO; +import com.guwan.backend.model.paper.dto.response.PaperListRespDTO; +import com.guwan.backend.model.paper.entity.Paper; + + +/** +*

+* 试卷业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 16:33 +*/ +public interface PaperService extends IService { + + /** + * 创建试卷 + * @param userId + * @param examId + * @return + */ + String createPaper(String userId, String examId); + + + /** + * 查找详情 + * @param paperId + * @return + */ + ExamDetailRespDTO paperDetail(String paperId); + + /** + * 考试结果 + * @param paperId + * @return + */ + ExamResultRespDTO paperResult(String paperId); + + /** + * 查找题目详情 + * @param paperId + * @param quId + * @return + */ + PaperQuDetailDTO findQuDetail(String paperId, String quId); + + /** + * 填充答案 + * @param reqDTO + */ + void fillAnswer(PaperAnswerDTO reqDTO); + + /** + * 交卷操作 + * @param paperId + * @return + */ + void handExam(String paperId); + + /** + * 试卷列表响应类 + * @param reqDTO + * @return + */ + IPage paging(PagingReqDTO reqDTO); + + /** + * 检测是否有进行中的考试 + * @param userId + * @return + */ + PaperDTO checkProcess(String userId); + +} diff --git a/src/main/java/com/guwan/backend/model/paper/service/impl/PaperQuAnswerServiceImpl.java b/src/main/java/com/guwan/backend/model/paper/service/impl/PaperQuAnswerServiceImpl.java new file mode 100644 index 0000000..cfd595b --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/service/impl/PaperQuAnswerServiceImpl.java @@ -0,0 +1,62 @@ +package com.guwan.backend.model.paper.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import com.guwan.backend.core.api.dto.PagingReqDTO; +import com.guwan.backend.model.paper.dto.PaperQuAnswerDTO; +import com.guwan.backend.model.paper.dto.ext.PaperQuAnswerExtDTO; +import com.guwan.backend.model.paper.entity.PaperQuAnswer; +import com.guwan.backend.model.paper.mapper.PaperQuAnswerMapper; +import com.guwan.backend.model.paper.service.PaperQuAnswerService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** +*

+* 语言设置 服务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 16:33 +*/ +@Service +public class PaperQuAnswerServiceImpl extends ServiceImpl implements PaperQuAnswerService { + + @Override + public IPage paging(PagingReqDTO reqDTO) { + + //创建分页对象 + IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); + + //查询条件 + QueryWrapper wrapper = new QueryWrapper<>(); + + //获得数据 + IPage page = this.page(query, wrapper); + //转换结果 + IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); + return pageData; + } + + @Override + public List listForExam(String paperId, String quId) { + return baseMapper.list(paperId, quId); + } + + @Override + public List listForFill(String paperId, String quId) { + //查询条件 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda() + .eq(PaperQuAnswer::getPaperId, paperId) + .eq(PaperQuAnswer::getQuId, quId); + + return this.list(wrapper); + } +} diff --git a/src/main/java/com/guwan/backend/model/paper/service/impl/PaperQuServiceImpl.java b/src/main/java/com/guwan/backend/model/paper/service/impl/PaperQuServiceImpl.java new file mode 100644 index 0000000..448e63f --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/service/impl/PaperQuServiceImpl.java @@ -0,0 +1,95 @@ +package com.guwan.backend.model.paper.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import com.guwan.backend.core.api.dto.PagingReqDTO; +import com.guwan.backend.core.BeanMapper; +import com.guwan.backend.model.paper.dto.PaperQuDTO; +import com.guwan.backend.model.paper.dto.ext.PaperQuDetailDTO; +import com.guwan.backend.model.paper.entity.PaperQu; +import com.guwan.backend.model.paper.mapper.PaperQuMapper; +import com.guwan.backend.model.paper.service.PaperQuService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** +*

+* 语言设置 服务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 16:33 +*/ +@Service +public class PaperQuServiceImpl extends ServiceImpl implements PaperQuService { + + @Override + public IPage paging(PagingReqDTO reqDTO) { + + //创建分页对象 + IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); + + //查询条件 + QueryWrapper wrapper = new QueryWrapper<>(); + + //获得数据 + IPage page = this.page(query, wrapper); + //转换结果 + IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); + return pageData; + } + + @Override + public List listByPaper(String paperId) { + + //查询条件 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(PaperQu::getPaperId, paperId) + .orderByAsc(PaperQu::getSort); + + List list = this.list(wrapper); + return BeanMapper.mapList(list, PaperQuDTO.class); + } + + @Override + public PaperQu findByKey(String paperId, String quId) { + //查询条件 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(PaperQu::getPaperId, paperId) + .eq(PaperQu::getQuId, quId); + + return this.getOne(wrapper, false); + } + + @Override + public void updateByKey(PaperQu qu) { + + //查询条件 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(PaperQu::getPaperId, qu.getPaperId()) + .eq(PaperQu::getQuId, qu.getQuId()); + + this.update(qu, wrapper); + } + + @Override + public int sumObjective(String paperId) { + return baseMapper.sumObjective(paperId); + } + + @Override + public int sumSubjective(String paperId) { + return baseMapper.sumSubjective(paperId); + } + + @Override + public List listForPaperResult(String paperId) { + return baseMapper.listByPaper(paperId); + } +} diff --git a/src/main/java/com/guwan/backend/model/paper/service/impl/PaperServiceImpl.java b/src/main/java/com/guwan/backend/model/paper/service/impl/PaperServiceImpl.java new file mode 100644 index 0000000..68edd63 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/paper/service/impl/PaperServiceImpl.java @@ -0,0 +1,537 @@ +package com.guwan.backend.model.paper.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import com.guwan.backend.core.api.ApiError; +import com.guwan.backend.core.api.dto.PagingReqDTO; +import com.guwan.backend.core.exception.ServiceException; +import com.guwan.backend.core.BeanMapper; +import com.guwan.backend.core.utils.CronUtils; +import com.guwan.backend.model.exam.dto.ExamDTO; +import com.guwan.backend.model.exam.dto.ExamRepoDTO; +import com.guwan.backend.model.exam.dto.ext.ExamRepoExtDTO; +import com.guwan.backend.model.exam.service.ExamService; +import com.guwan.backend.model.paper.dto.PaperDTO; +import com.guwan.backend.model.paper.dto.PaperQuDTO; +import com.guwan.backend.model.paper.dto.ext.PaperQuAnswerExtDTO; +import com.guwan.backend.model.paper.dto.ext.PaperQuDetailDTO; +import com.guwan.backend.model.paper.dto.request.PaperAnswerDTO; +import com.guwan.backend.model.paper.dto.request.PaperListReqDTO; +import com.guwan.backend.model.paper.dto.response.ExamDetailRespDTO; +import com.guwan.backend.model.paper.dto.response.ExamResultRespDTO; +import com.guwan.backend.model.paper.dto.response.PaperListRespDTO; +import com.guwan.backend.model.paper.entity.Paper; +import com.guwan.backend.model.paper.entity.PaperQu; +import com.guwan.backend.model.paper.entity.PaperQuAnswer; +import com.guwan.backend.model.paper.enums.ExamState; +import com.guwan.backend.model.paper.enums.PaperState; +import com.guwan.backend.model.paper.job.BreakExamJob; +import com.guwan.backend.model.paper.mapper.PaperMapper; +import com.guwan.backend.model.paper.service.PaperQuAnswerService; +import com.guwan.backend.model.paper.service.PaperQuService; +import com.guwan.backend.model.paper.service.PaperService; +import com.guwan.backend.model.qu.entity.Qu; +import com.guwan.backend.model.qu.entity.QuAnswer; +import com.guwan.backend.model.qu.enums.QuType; +import com.guwan.backend.model.qu.service.QuAnswerService; +import com.guwan.backend.model.qu.service.QuService; +import com.guwan.backend.model.user.book.service.UserBookService; +import com.guwan.backend.model.user.exam.service.UserExamService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.util.*; + +/** +*

+* 语言设置 服务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 16:33 +*/ +@Service +public class PaperServiceImpl extends ServiceImpl implements PaperService { + + + @Autowired + private SysUserService sysUserService; + + @Autowired + private ExamService examService; + + @Autowired + private QuService quService; + + @Autowired + private QuAnswerService quAnswerService; + + @Autowired + private PaperService paperService; + + @Autowired + private PaperQuService paperQuService; + + @Autowired + private PaperQuAnswerService paperQuAnswerService; + + @Autowired + private UserBookService userBookService; + + @Autowired + private ExamRepoService examRepoService; + + @Autowired + private UserExamService userExamService; + + @Autowired + private JobService jobService; + + /** + * 展示的选项,ABC这样 + */ + private static List ABC = Arrays.asList(new String[]{ + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K","L","M","N","O","P","Q","R","S","T","U","V","W","X" + ,"Y","Z" + }); + + + + + + @Transactional(rollbackFor = Exception.class) + @Override + public String createPaper(String userId, String examId) { + + // 校验是否有正在考试的试卷 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda() + .eq(Paper::getUserId, userId) + .eq(Paper::getState, PaperState.ING); + + int exists = this.count(wrapper); + + + if (exists > 0) { + throw new ServiceException(ApiError.ERROR_20010002); + } + + // 查找考试 + ExamDTO exam = examService.findById(examId); + + if(exam == null){ + throw new ServiceException(1, "考试不存在!"); + } + + if(!ExamState.ENABLE.equals(exam.getState())){ + throw new ServiceException(1, "考试状态不正确!"); + } + + // 考试题目列表 + List quList = this.generateByRepo(examId); + + if(CollectionUtils.isEmpty(quList)){ + throw new ServiceException(1, "规则不正确,无对应的考题!"); + } + + //保存试卷内容 + Paper paper = this.savePaper(userId, exam, quList); + + // 强制交卷任务 + String jobName = JobPrefix.BREAK_EXAM + paper.getId(); + jobService.addCronJob(BreakExamJob.class, jobName, CronUtils.dateToCron(paper.getLimitTime()), paper.getId()); + + return paper.getId(); + } + + @Override + public ExamDetailRespDTO paperDetail(String paperId) { + + + ExamDetailRespDTO respDTO = new ExamDetailRespDTO(); + + // 试题基本信息 + Paper paper = paperService.getById(paperId); + BeanMapper.copy(paper, respDTO); + + // 查找题目列表 + List list = paperQuService.listByPaper(paperId); + + List radioList = new ArrayList<>(); + List multiList = new ArrayList<>(); + List judgeList = new ArrayList<>(); + for(PaperQuDTO item: list){ + if(QuType.RADIO.equals(item.getQuType())){ + radioList.add(item); + } + if(QuType.MULTI.equals(item.getQuType())){ + multiList.add(item); + } + if(QuType.JUDGE.equals(item.getQuType())){ + judgeList.add(item); + } + } + + respDTO.setRadioList(radioList); + respDTO.setMultiList(multiList); + respDTO.setJudgeList(judgeList); + return respDTO; + } + + @Override + public ExamResultRespDTO paperResult(String paperId) { + + ExamResultRespDTO respDTO = new ExamResultRespDTO(); + + // 试题基本信息 + Paper paper = paperService.getById(paperId); + BeanMapper.copy(paper, respDTO); + + List quList = paperQuService.listForPaperResult(paperId); + respDTO.setQuList(quList); + + return respDTO; + } + + @Override + public PaperQuDetailDTO findQuDetail(String paperId, String quId) { + + PaperQuDetailDTO respDTO = new PaperQuDetailDTO(); + // 问题 + Qu qu = quService.getById(quId); + + // 基本信息 + PaperQu paperQu = paperQuService.findByKey(paperId, quId); + BeanMapper.copy(paperQu, respDTO); + respDTO.setContent(qu.getContent()); + respDTO.setImage(qu.getImage()); + + // 答案列表 + List list = paperQuAnswerService.listForExam(paperId, quId); + respDTO.setAnswerList(list); + + return respDTO; + } + + + /** + * 题库组题方式产生题目列表 + * @param examId + * @return + */ + private List generateByRepo(String examId){ + + // 查找规则指定的题库 + List list = examRepoService.listByExam(examId); + + //最终的题目列表 + List quList = new ArrayList<>(); + + //排除ID,避免题目重复 + List excludes = new ArrayList<>(); + excludes.add("none"); + + if (!CollectionUtils.isEmpty(list)) { + for (ExamRepoExtDTO item : list) { + + // 单选题 + if(item.getRadioCount() > 0){ + List radioList = quService.listByRandom(item.getRepoId(), QuType.RADIO, excludes, item.getRadioCount()); + for (Qu qu : radioList) { + PaperQu paperQu = this.processPaperQu(item, qu); + quList.add(paperQu); + excludes.add(qu.getId()); + } + } + + //多选题 + if(item.getMultiCount() > 0) { + List multiList = quService.listByRandom(item.getRepoId(), QuType.MULTI, excludes, + item.getMultiCount()); + for (Qu qu : multiList) { + PaperQu paperQu = this.processPaperQu(item, qu); + quList.add(paperQu); + excludes.add(qu.getId()); + } + } + + // 判断题 + if(item.getJudgeCount() > 0) { + List judgeList = quService.listByRandom(item.getRepoId(), QuType.JUDGE, excludes, + item.getJudgeCount()); + for (Qu qu : judgeList) { + PaperQu paperQu = this.processPaperQu(item, qu); + quList.add(paperQu); + excludes.add(qu.getId()); + } + } + } + } + return quList; + } + + + + /** + * 填充试题题目信息 + * @param repo + * @param qu + * @return + */ + private PaperQu processPaperQu(ExamRepoDTO repo, Qu qu) { + + //保存试题信息 + PaperQu paperQu = new PaperQu(); + paperQu.setQuId(qu.getId()); + paperQu.setAnswered(false); + paperQu.setIsRight(false); + paperQu.setQuType(qu.getQuType()); + + if (QuType.RADIO.equals(qu.getQuType())) { + paperQu.setScore(repo.getRadioScore()); + paperQu.setActualScore(repo.getRadioScore()); + } + + if (QuType.MULTI.equals(qu.getQuType())) { + paperQu.setScore(repo.getMultiScore()); + paperQu.setActualScore(repo.getMultiScore()); + } + + if (QuType.JUDGE.equals(qu.getQuType())) { + paperQu.setScore(repo.getJudgeScore()); + paperQu.setActualScore(repo.getJudgeScore()); + } + + return paperQu; + } + + + /** + * 保存试卷 + * @param userId + * @param exam + * @param quList + * @return + */ + private Paper savePaper(String userId, ExamDTO exam, List quList) { + + + // 查找用户 + SysUser user = sysUserService.getById(userId); + + //保存试卷基本信息 + Paper paper = new Paper(); + paper.setDepartId(user.getDepartId()); + paper.setExamId(exam.getId()); + paper.setTitle(exam.getTitle()); + paper.setTotalScore(exam.getTotalScore()); + paper.setTotalTime(exam.getTotalTime()); + paper.setUserScore(0); + paper.setUserId(userId); + paper.setCreateTime(new Date()); + paper.setUpdateTime(new Date()); + paper.setQualifyScore(exam.getQualifyScore()); + paper.setState(PaperState.ING); + paper.setHasSaq(false); + + // 截止时间 + Calendar cl = Calendar.getInstance(); + cl.setTimeInMillis(System.currentTimeMillis()); + cl.add(Calendar.MINUTE, exam.getTotalTime()); + paper.setLimitTime(cl.getTime()); + + paperService.save(paper); + + if (!CollectionUtils.isEmpty(quList)) { + this.savePaperQu(paper.getId(), quList); + } + + return paper; + } + + + + /** + * 保存试卷试题列表 + * @param paperId + * @param quList + */ + private void savePaperQu(String paperId, List quList){ + + List batchQuList = new ArrayList<>(); + List batchAnswerList = new ArrayList<>(); + + int sort = 0; + for (PaperQu item : quList) { + + item.setPaperId(paperId); + item.setSort(sort); + item.setId(IdWorker.getIdStr()); + + //回答列表 + List answerList = quAnswerService.listAnswerByRandom(item.getQuId()); + + if (!CollectionUtils.isEmpty(answerList)) { + + int ii = 0; + for (QuAnswer answer : answerList) { + PaperQuAnswer paperQuAnswer = new PaperQuAnswer(); + paperQuAnswer.setId(UUID.randomUUID().toString()); + paperQuAnswer.setPaperId(paperId); + paperQuAnswer.setQuId(answer.getQuId()); + paperQuAnswer.setAnswerId(answer.getId()); + paperQuAnswer.setChecked(false); + paperQuAnswer.setSort(ii); + paperQuAnswer.setAbc(ABC.get(ii)); + paperQuAnswer.setIsRight(answer.getIsRight()); + ii++; + batchAnswerList.add(paperQuAnswer); + } + } + + batchQuList.add(item); + sort++; + } + + //添加问题 + paperQuService.saveBatch(batchQuList); + + //批量添加问题答案 + paperQuAnswerService.saveBatch(batchAnswerList); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void fillAnswer(PaperAnswerDTO reqDTO) { + + + // 未作答 + if(CollectionUtils.isEmpty(reqDTO.getAnswers()) + && StringUtils.isBlank(reqDTO.getAnswer())){ + return; + } + + //查找答案列表 + List list = paperQuAnswerService.listForFill(reqDTO.getPaperId(), reqDTO.getQuId()); + + //是否正确 + boolean right = true; + + //更新正确答案 + for (PaperQuAnswer item : list) { + + if (reqDTO.getAnswers().contains(item.getId())) { + item.setChecked(true); + } else { + item.setChecked(false); + } + + //有一个对不上就是错的 + if (item.getIsRight()!=null && !item.getIsRight().equals(item.getChecked())) { + right = false; + } + paperQuAnswerService.updateById(item); + } + + //修改为已回答 + PaperQu qu = new PaperQu(); + qu.setQuId(reqDTO.getQuId()); + qu.setPaperId(reqDTO.getPaperId()); + qu.setIsRight(right); + qu.setAnswer(reqDTO.getAnswer()); + qu.setAnswered(true); + + paperQuService.updateByKey(qu); + + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void handExam(String paperId) { + + //获取试卷信息 + Paper paper = paperService.getById(paperId); + + //如果不是正常的,抛出异常 + if(!PaperState.ING.equals(paper.getState())){ + throw new ServiceException(1, "试卷状态不正确!"); + } + + // 客观分 + int objScore = paperQuService.sumObjective(paperId); + paper.setObjScore(objScore); + paper.setUserScore(objScore); + + // 主观分,因为要阅卷,所以给0 + paper.setSubjScore(0); + + // 待阅卷 + if(paper.getHasSaq()) { + paper.setState(PaperState.WAIT_OPT); + }else { + + // 同步保存考试成绩 + userExamService.joinResult(paper.getUserId(), paper.getExamId(), objScore, objScore>=paper.getQualifyScore()); + + paper.setState(PaperState.FINISHED); + } + paper.setUpdateTime(new Date()); + + //计算考试时长 + Calendar cl = Calendar.getInstance(); + cl.setTimeInMillis(System.currentTimeMillis()); + int userTime = (int)((System.currentTimeMillis() - paper.getCreateTime().getTime()) / 1000 / 60); + if(userTime == 0){ + userTime = 1; + } + paper.setUserTime(userTime); + + //更新试卷 + paperService.updateById(paper); + + + // 终止定时任务 + String name = JobPrefix.BREAK_EXAM + paperId; + jobService.deleteJob(name, JobGroup.SYSTEM); + + //把打错的问题加入错题本 + List list = paperQuService.listByPaper(paperId); + for(PaperQuDTO qu: list){ + // 主观题和对的都不加入错题库 + if(qu.getIsRight()){ + continue; + } + //加入错题本 + new Thread(() -> userBookService.addBook(paper.getExamId(), qu.getQuId())).run(); + } + } + + @Override + public IPage paging(PagingReqDTO reqDTO) { + return baseMapper.paging(reqDTO.toPage(), reqDTO.getParams()); + } + + + @Override + public PaperDTO checkProcess(String userId) { + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda() + .eq(Paper::getUserId, userId) + .eq(Paper::getState, PaperState.ING); + + Paper paper = this.getOne(wrapper, false); + + if (paper != null) { + return BeanMapper.map(paper, PaperDTO.class); + } + + return null; + } +} diff --git a/src/main/java/com/guwan/backend/model/qu/controller/QuController.java b/src/main/java/com/guwan/backend/model/qu/controller/QuController.java new file mode 100644 index 0000000..f30efbc --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/controller/QuController.java @@ -0,0 +1,316 @@ +package com.guwan.backend.model.qu.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.google.common.collect.Lists; +import com.yf.exam.core.api.ApiRest; +import com.yf.exam.core.api.controller.BaseController; +import com.yf.exam.core.api.dto.BaseIdReqDTO; +import com.yf.exam.core.api.dto.BaseIdRespDTO; +import com.yf.exam.core.api.dto.BaseIdsReqDTO; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.core.exception.ServiceException; +import com.yf.exam.core.utils.excel.ExportExcel; +import com.yf.exam.core.utils.excel.ImportExcel; +import com.yf.exam.modules.qu.dto.QuDTO; +import com.yf.exam.modules.qu.dto.export.QuExportDTO; +import com.yf.exam.modules.qu.dto.ext.QuDetailDTO; +import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO; +import com.yf.exam.modules.qu.service.QuService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.shiro.authz.annotation.RequiresRoles; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +/** +*

+* 问题题目控制器 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:25 +*/ +@Api(tags={"问题题目"}) +@RestController +@RequestMapping("/exam/api/qu/qu") +public class QuController extends BaseController { + + @Autowired + private QuService baseService; + + /** + * 添加或修改 + * + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "添加或修改") + @RequestMapping(value = "/save", method = {RequestMethod.POST}) + public ApiRest save(@RequestBody QuDetailDTO reqDTO) { + baseService.save(reqDTO); + return super.success(); + } + + /** + * 批量删除 + * + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "批量删除") + @RequestMapping(value = "/delete", method = {RequestMethod.POST}) + public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) { + //根据ID删除 + baseService.delete(reqDTO.getIds()); + return super.success(); + } + + /** + * 查找详情 + * + * @param reqDTO + * @return + */ + @ApiOperation(value = "查找详情") + @RequestMapping(value = "/detail", method = {RequestMethod.POST}) + public ApiRest detail(@RequestBody BaseIdReqDTO reqDTO) { + QuDetailDTO dto = baseService.detail(reqDTO.getId()); + return super.success(dto); + } + + /** + * 分页查找 + * + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "分页查找") + @RequestMapping(value = "/paging", method = {RequestMethod.POST}) + public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { + + //分页查询并转换 + IPage page = baseService.paging(reqDTO); + + return super.success(page); + } + + + /** + * 导出excel文件 + */ + @RequiresRoles("sa") + @ResponseBody + @RequestMapping(value = "/export") + public ApiRest exportFile(HttpServletResponse response, @RequestBody QuQueryReqDTO reqDTO) { + + + // 导出文件名 + String fileName = "导出的试题-" + System.currentTimeMillis() + ".xlsx"; + + try { + + int no = 0; + String quId = ""; + List list = baseService.listForExport(reqDTO); + for (QuExportDTO item : list) { + if (!quId.equals(item.getQId())) { + quId = item.getQId(); + no += 1; + } else { + item.setQuType("0"); + item.setQContent(""); + item.setQAnalysis(""); + item.setRepoList(null); + item.setQImage(""); + item.setQVideo(""); + } + item.setNo(String.valueOf(no)); + } + new ExportExcel("试题", QuExportDTO.class).setDataList(list).write(response, fileName).dispose(); + return super.success(); + } catch (Exception e) { + return failure(e.getMessage()); + } + } + + /** + * 导入Excel + * + * @param file + * @return + */ + @RequiresRoles("sa") + @ResponseBody + @RequestMapping(value = "/import") + public ApiRest importFile(@RequestParam("file") MultipartFile file) { + + try { + + ImportExcel ei = new ImportExcel(file, 1, 0); + List list = ei.getDataList(QuExportDTO.class); + + // 校验数据 + this.checkExcel(list); + + // 导入数据条数 + baseService.importExcel(list); + + // 导入成功 + return super.success(); + + } catch (IOException e) { + + } catch (InvalidFormatException e) { + + } catch (IllegalAccessException e) { + + } catch (InstantiationException e) { + + } + + return super.failure(); + } + + /** + * 校验Excel + * + * @param list + * @throws Exception + */ + private void checkExcel(List list) throws ServiceException { + + // 约定第三行开始导入 + int line = 3; + StringBuffer sb = new StringBuffer(); + + if (CollectionUtils.isEmpty(list)) { + throw new ServiceException(1, "您导入的数据似乎是一个空表格!"); + } + + Integer quNo = null; + for (QuExportDTO item : list) { + + System.out.println(item.getNo()); + if (StringUtils.isBlank(item.getNo())) { + line++; + continue; + } + + System.out.println(item.getQContent()); + Integer no; + + try { + no = Integer.parseInt(item.getNo()); + } catch (Exception e) { + line++; + continue; + } + + if (no == null) { + sb.append("第" + line + "行,题目序号不能为空!
"); + } + + if (quNo == null || !quNo.equals(no)) { + + if (item.getQuType() == null) { + sb.append("第" + line + "行,题目类型不能为空
"); + } + + if (StringUtils.isBlank(item.getQContent())) { + sb.append("第" + line + "行,题目内容不能为空
"); + } + + if (CollectionUtils.isEmpty(item.getRepoList())) { + sb.append("第" + line + "行,题目必须包含一个题库
"); + } + } + + if (StringUtils.isBlank(item.getAIsRight())) { + sb.append("第" + line + "行,选项是否正确不能为空
"); + } + + if (StringUtils.isBlank(item.getAContent()) && StringUtils.isBlank(item.getAImage())) { + sb.append("第" + line + "行,选项内容和选项图片必须有一个不为空
"); + } + + quNo = no; + line++; + } + + // 存在错误 + if (!"".equals(sb.toString())) { + throw new ServiceException(1, sb.toString()); + } + } + + /** + * 下载导入试题数据模板 + */ + @ResponseBody + @RequestMapping(value = "import/template") + public ApiRest importFileTemplate(HttpServletResponse response) { + try { + String fileName = "试题导入模板.xlsx"; + List list = Lists.newArrayList(); + + QuExportDTO l1 = new QuExportDTO(); + l1.setNo("正式导入,请删除此说明行:数字,相同的数字表示同一题的序列"); + l1.setQContent("问题内容"); + l1.setQAnalysis("整个问题的解析"); + l1.setQuType("只能填写1、2、3、4;1表示单选题,2表示多选题,3表示判断题,4表示主观题"); + l1.setQImage("题目图片,完整URL,多个用逗号隔开,限制10个"); + l1.setQVideo("题目视频,完整URL,只限一个"); + l1.setAImage("答案图片,完整URL,只限一个"); + l1.setRepoList(Arrays.asList(new String[]{"已存在题库的ID,多个用逗号隔开,题库ID错误无法导入"})); + l1.setAContent("候选答案1"); + l1.setAIsRight("只能填写0或1,0表示否,1表示是"); + l1.setAAnalysis("这个项是正确的"); + + + QuExportDTO l2 = new QuExportDTO(); + l2.setQContent("找出以下可以被2整除的数(多选)"); + l2.setQAnalysis("最基本的数学题,不做过多解析"); + l2.setQuType("2"); + l2.setNo("1"); + l2.setAIsRight("1"); + l2.setAContent("数字:2"); + l2.setAAnalysis("2除以2=1,对的"); + + QuExportDTO l3 = new QuExportDTO(); + l3.setNo("1"); + l3.setAIsRight("0"); + l3.setAContent("数字:3"); + l3.setAAnalysis("3除以2=1.5,不能被整除"); + + QuExportDTO l4 = new QuExportDTO(); + l4.setNo("1"); + l4.setAIsRight("1"); + l4.setAContent("数字:6"); + l4.setAAnalysis("6除以2=3,对的"); + + + + list.add(l1); + list.add(l2); + list.add(l3); + list.add(l4); + + new ExportExcel("试题数据", QuExportDTO.class, 1).setDataList(list).write(response, fileName).dispose(); + return super.success(); + } catch (Exception e) { + return super.failure("导入模板下载失败!失败信息:"+e.getMessage()); + } + } +} diff --git a/src/main/java/com/guwan/backend/model/qu/dto/QuAnswerDTO.java b/src/main/java/com/guwan/backend/model/qu/dto/QuAnswerDTO.java new file mode 100644 index 0000000..47646c6 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/dto/QuAnswerDTO.java @@ -0,0 +1,42 @@ +package com.guwan.backend.model.qu.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** +*

+* 候选答案请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +@Data +@ApiModel(value="候选答案", description="候选答案") +public class QuAnswerDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "答案ID", required=true) + private String id; + + @ApiModelProperty(value = "问题ID", required=true) + private String quId; + + @ApiModelProperty(value = "是否正确", required=true) + private Boolean isRight; + + @ApiModelProperty(value = "选项图片", required=true) + private String image; + + @ApiModelProperty(value = "答案内容", required=true) + private String content; + + @ApiModelProperty(value = "答案分析", required=true) + private String analysis; + +} diff --git a/src/main/java/com/guwan/backend/model/qu/dto/QuDTO.java b/src/main/java/com/guwan/backend/model/qu/dto/QuDTO.java new file mode 100644 index 0000000..cec2699 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/dto/QuDTO.java @@ -0,0 +1,53 @@ +package com.guwan.backend.model.qu.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** +*

+* 问题题目请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +@Data +@ApiModel(value="问题题目", description="问题题目") +public class QuDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "题目ID", required=true) + private String id; + + @ApiModelProperty(value = "题目类型", required=true) + private Integer quType; + + @ApiModelProperty(value = "1普通,2较难", required=true) + private Integer level; + + @ApiModelProperty(value = "题目图片", required=true) + private String image; + + @ApiModelProperty(value = "题目内容", required=true) + private String content; + + + @ApiModelProperty(value = "创建时间", required=true) + private Date createTime; + + @ApiModelProperty(value = "更新时间", required=true) + private Date updateTime; + + @ApiModelProperty(value = "题目备注", required=true) + private String remark; + + @ApiModelProperty(value = "整题解析", required=true) + private String analysis; + +} diff --git a/src/main/java/com/guwan/backend/model/qu/dto/QuRepoDTO.java b/src/main/java/com/guwan/backend/model/qu/dto/QuRepoDTO.java new file mode 100644 index 0000000..b7234c0 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/dto/QuRepoDTO.java @@ -0,0 +1,38 @@ +package com.guwan.backend.model.qu.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** +*

+* 试题题库请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +@Data +@ApiModel(value="试题题库", description="试题题库") +public class QuRepoDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + private String id; + + @ApiModelProperty(value = "试题", required=true) + private String quId; + + @ApiModelProperty(value = "归属题库", required=true) + private String repoId; + + @ApiModelProperty(value = "题目类型", required=true) + private Integer quType; + + @ApiModelProperty(value = "排序", required=true) + private Integer sort; + +} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/model/qu/dto/export/QuExportDTO.java b/src/main/java/com/guwan/backend/model/qu/dto/export/QuExportDTO.java new file mode 100644 index 0000000..d2a3191 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/dto/export/QuExportDTO.java @@ -0,0 +1,45 @@ +package com.guwan.backend.model.qu.dto.export; + +import com.yf.exam.core.utils.excel.annotation.ExcelField; +import com.yf.exam.core.utils.excel.fieldtype.ListType; +import lombok.Data; + +import java.util.List; + +/** + * 用于导出的数据结构 + * @author bool + */ +@Data +public class QuExportDTO { + + private static final long serialVersionUID = 1L; + + /** + * + */ + private String qId; + + @ExcelField(title="题目序号", align=2, sort=1) + private String no; + @ExcelField(title="题目类型", align=2, sort=2) + private String quType; + @ExcelField(title="题目内容", align=2, sort=3) + private String qContent; + @ExcelField(title="整体解析", align=2, sort=4) + private String qAnalysis; + @ExcelField(title="题目图片", align=2, sort=5) + private String qImage; + @ExcelField(title="题目视频", align=2, sort=6) + private String qVideo; + @ExcelField(title="所属题库", align=2, sort=7, fieldType = ListType.class) + private List repoList; + @ExcelField(title="是否正确项", align=2, sort=8) + private String aIsRight; + @ExcelField(title="选项内容", align=2, sort=9) + private String aContent; + @ExcelField(title="选项解析", align=2, sort=10) + private String aAnalysis; + @ExcelField(title="选项图片", align=2, sort=11) + private String aImage; +} diff --git a/src/main/java/com/guwan/backend/model/qu/dto/export/QuImportDTO.java b/src/main/java/com/guwan/backend/model/qu/dto/export/QuImportDTO.java new file mode 100644 index 0000000..45cebb3 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/dto/export/QuImportDTO.java @@ -0,0 +1,23 @@ +package com.guwan.backend.model.qu.dto.export; + +import com.yf.exam.modules.qu.dto.QuAnswerDTO; +import lombok.Data; + +import java.util.List; + +/** + * 用于导出的数据结构 + * @author bool + */ +@Data +public class QuImportDTO { + + private static final long serialVersionUID = 1L; + + private String quType; + private String qContent; + private String qAnalysis; + private String qImage; + private String repoName; + private List answerList; +} diff --git a/src/main/java/com/guwan/backend/model/qu/dto/ext/QuDetailDTO.java b/src/main/java/com/guwan/backend/model/qu/dto/ext/QuDetailDTO.java new file mode 100644 index 0000000..1f4ab90 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/dto/ext/QuDetailDTO.java @@ -0,0 +1,33 @@ +package com.guwan.backend.model.qu.dto.ext; + +import com.yf.exam.modules.qu.dto.QuAnswerDTO; +import com.yf.exam.modules.qu.dto.QuDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** +*

+* 问题题目请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +@Data +@ApiModel(value="问题题目详情", description="问题题目详情") +public class QuDetailDTO extends QuDTO { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "备选项列表", required=true) + private List answerList; + + @ApiModelProperty(value = "题库列表", required=true) + private List repoIds; + + +} diff --git a/src/main/java/com/guwan/backend/model/qu/dto/request/QuQueryReqDTO.java b/src/main/java/com/guwan/backend/model/qu/dto/request/QuQueryReqDTO.java new file mode 100644 index 0000000..c9ec11f --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/dto/request/QuQueryReqDTO.java @@ -0,0 +1,38 @@ +package com.guwan.backend.model.qu.dto.request; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** +*

+* 问题题目请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +@Data +@ApiModel(value="题目查询请求类", description="题目查询请求类") +public class QuQueryReqDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "题目类型") + private Integer quType; + + @ApiModelProperty(value = "归属题库") + private List repoIds; + + @ApiModelProperty(value = "题目内容") + private String content; + + @ApiModelProperty(value = "排除ID列表") + private List excludes; + + +} diff --git a/src/main/java/com/guwan/backend/model/qu/dto/request/QuRepoBatchReqDTO.java b/src/main/java/com/guwan/backend/model/qu/dto/request/QuRepoBatchReqDTO.java new file mode 100644 index 0000000..6d39944 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/dto/request/QuRepoBatchReqDTO.java @@ -0,0 +1,34 @@ +package com.guwan.backend.model.qu.dto.request; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** +*

+* 问题题目请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +@Data +@ApiModel(value="试题题库批量操作类", description="试题题库批量操作类") +public class QuRepoBatchReqDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "题目ID", required=true) + private List quIds; + + @ApiModelProperty(value = "题目类型", required=true) + private List repoIds; + + @ApiModelProperty(value = "是否移除,否就新增;是就移除", required=true) + private Boolean remove; + +} diff --git a/src/main/java/com/guwan/backend/model/qu/entity/Qu.java b/src/main/java/com/guwan/backend/model/qu/entity/Qu.java new file mode 100644 index 0000000..c20b6b6 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/entity/Qu.java @@ -0,0 +1,75 @@ +package com.guwan.backend.model.qu.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +import java.util.Date; + +/** +*

+* 问题题目实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +@Data +@TableName("el_qu") +public class Qu extends Model { + + private static final long serialVersionUID = 1L; + + /** + * 题目ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 题目类型 + */ + @TableField("qu_type") + private Integer quType; + + /** + * 1普通,2较难 + */ + private Integer level; + + /** + * 题目图片 + */ + private String image; + + /** + * 题目内容 + */ + private String content; + + /** + * 创建时间 + */ + @TableField("create_time") + private Date createTime; + + /** + * 更新时间 + */ + @TableField("update_time") + private Date updateTime; + + /** + * 题目备注 + */ + private String remark; + + /** + * 整题解析 + */ + private String analysis; + +} diff --git a/src/main/java/com/guwan/backend/model/qu/entity/QuAnswer.java b/src/main/java/com/guwan/backend/model/qu/entity/QuAnswer.java new file mode 100644 index 0000000..4f9f4c3 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/entity/QuAnswer.java @@ -0,0 +1,58 @@ +package com.guwan.backend.model.qu.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** +*

+* 候选答案实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +@Data +@TableName("el_qu_answer") +public class QuAnswer extends Model { + + private static final long serialVersionUID = 1L; + + /** + * 答案ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 问题ID + */ + @TableField("qu_id") + private String quId; + + /** + * 是否正确 + */ + @TableField("is_right") + private Boolean isRight; + + /** + * 选项图片 + */ + private String image; + + /** + * 答案内容 + */ + private String content; + + + /** + * 答案分析 + */ + private String analysis; + +} diff --git a/src/main/java/com/guwan/backend/model/qu/entity/QuRepo.java b/src/main/java/com/guwan/backend/model/qu/entity/QuRepo.java new file mode 100644 index 0000000..7418d90 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/entity/QuRepo.java @@ -0,0 +1,50 @@ +package com.guwan.backend.model.qu.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** +*

+* 试题题库实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +@Data +@TableName("el_qu_repo") +public class QuRepo extends Model { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 试题 + */ + @TableField("qu_id") + private String quId; + + /** + * 归属题库 + */ + @TableField("repo_id") + private String repoId; + + /** + * 题目类型 + */ + @TableField("qu_type") + private Integer quType; + + /** + * 排序 + */ + private Integer sort; + +} diff --git a/src/main/java/com/guwan/backend/model/qu/enums/QuType.java b/src/main/java/com/guwan/backend/model/qu/enums/QuType.java new file mode 100644 index 0000000..3f45534 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/enums/QuType.java @@ -0,0 +1,26 @@ +package com.guwan.backend.model.qu.enums; + + +/** + * 题目类型 + * @author bool + * @date 2019-10-30 13:11 + */ +public interface QuType { + + /** + * 单选题 + */ + Integer RADIO = 1; + + /** + * 多选题 + */ + Integer MULTI = 2; + + /** + * 判断题 + */ + Integer JUDGE = 3; + +} diff --git a/src/main/java/com/guwan/backend/model/qu/mapper/QuAnswerMapper.java b/src/main/java/com/guwan/backend/model/qu/mapper/QuAnswerMapper.java new file mode 100644 index 0000000..0872594 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/mapper/QuAnswerMapper.java @@ -0,0 +1,16 @@ +package com.guwan.backend.model.qu.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yf.exam.modules.qu.entity.QuAnswer; + +/** +*

+* 候选答案Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +public interface QuAnswerMapper extends BaseMapper { + +} diff --git a/src/main/java/com/guwan/backend/model/qu/mapper/QuMapper.java b/src/main/java/com/guwan/backend/model/qu/mapper/QuMapper.java new file mode 100644 index 0000000..4dcf2cb --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/mapper/QuMapper.java @@ -0,0 +1,56 @@ +package com.guwan.backend.model.qu.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.yf.exam.modules.qu.dto.QuDTO; +import com.yf.exam.modules.qu.dto.export.QuExportDTO; +import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO; +import com.yf.exam.modules.qu.entity.Qu; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** +*

+* 问题题目Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +public interface QuMapper extends BaseMapper { + + + + /** + * 随机抽取题库的数据 + * @param repoId + * @param quType + * @param level + * @param excludes 要排除的ID列表 + * @param size + * @return + */ + List listByRandom(@Param("repoId") String repoId, + @Param("quType") Integer quType, + @Param("excludes") List excludes, + @Param("size") Integer size); + + /** + * 查找导出列表 + * @param query + * @return + */ + List listForExport(@Param("query") QuQueryReqDTO query); + + /** + * 分页查找 + * @param page + * @param query + * @return + */ + IPage paging(Page page, @Param("query") QuQueryReqDTO query); + + +} diff --git a/src/main/java/com/guwan/backend/model/qu/mapper/QuRepoMapper.java b/src/main/java/com/guwan/backend/model/qu/mapper/QuRepoMapper.java new file mode 100644 index 0000000..514f9f9 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/mapper/QuRepoMapper.java @@ -0,0 +1,16 @@ +package com.guwan.backend.model.qu.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yf.exam.modules.qu.entity.QuRepo; + +/** +*

+* 试题题库Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +public interface QuRepoMapper extends BaseMapper { + +} diff --git a/src/main/java/com/guwan/backend/model/qu/service/QuAnswerService.java b/src/main/java/com/guwan/backend/model/qu/service/QuAnswerService.java new file mode 100644 index 0000000..31da2c8 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/service/QuAnswerService.java @@ -0,0 +1,48 @@ +package com.guwan.backend.model.qu.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.qu.dto.QuAnswerDTO; +import com.yf.exam.modules.qu.entity.QuAnswer; + +import java.util.List; + +/** +*

+* 候选答案业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +public interface QuAnswerService extends IService { + + /** + * 分页查询数据 + * @param reqDTO + * @return + */ + IPage paging(PagingReqDTO reqDTO); + + /** + * 根据题目ID查询答案并随机 + * @param quId + * @return + */ + List listAnswerByRandom(String quId); + + /** + * 根据问题查找答案 + * @param quId + * @return + */ + List listByQu(String quId); + + /** + * 保存试题 + * @param quId + * @param list + */ + void saveAll(String quId, List list); +} diff --git a/src/main/java/com/guwan/backend/model/qu/service/QuRepoService.java b/src/main/java/com/guwan/backend/model/qu/service/QuRepoService.java new file mode 100644 index 0000000..9b85f39 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/service/QuRepoService.java @@ -0,0 +1,59 @@ +package com.guwan.backend.model.qu.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.qu.dto.QuRepoDTO; +import com.yf.exam.modules.qu.dto.request.QuRepoBatchReqDTO; +import com.yf.exam.modules.qu.entity.QuRepo; + +import java.util.List; + +/** +*

+* 试题题库业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +public interface QuRepoService extends IService { + + /** + * 分页查询数据 + * @param reqDTO + * @return + */ + IPage paging(PagingReqDTO reqDTO); + + /** + * 保存全部列表 + * @param quId + * @param quType + * @param ids + */ + void saveAll(String quId, Integer quType, List ids); + + /** + * 根据问题查找题库 + * @param quId + * @return + */ + List listByQu(String quId); + + /** + * 根据题库查找题目ID列表 + * @param repoId + * @param quType + * @param rand + * @return + */ + List listByRepo(String repoId, Integer quType, boolean rand); + + /** + * 批量操作 + * @param reqDTO + */ + void batchAction(QuRepoBatchReqDTO reqDTO); + +} diff --git a/src/main/java/com/guwan/backend/model/qu/service/QuService.java b/src/main/java/com/guwan/backend/model/qu/service/QuService.java new file mode 100644 index 0000000..413ac87 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/service/QuService.java @@ -0,0 +1,76 @@ +package com.guwan.backend.model.qu.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.qu.dto.QuDTO; +import com.yf.exam.modules.qu.dto.export.QuExportDTO; +import com.yf.exam.modules.qu.dto.ext.QuDetailDTO; +import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO; +import com.yf.exam.modules.qu.entity.Qu; + +import java.util.List; + +/** +*

+* 问题题目业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +public interface QuService extends IService { + + /** + * 分页查询数据 + * @param reqDTO + * @return + */ + IPage paging(PagingReqDTO reqDTO); + + /** + * 删除试题 + * @param ids + */ + void delete(List ids); + + /** + * 随机抽取题库的数据 + * @param repoId + * @param quType + * @param excludes 要排除的ID列表 + * @param size + * @return + */ + List listByRandom(String repoId, + Integer quType, + List excludes, + Integer size); + + /** + * 问题详情 + * @param id + * @return + */ + QuDetailDTO detail(String id); + + /** + * 保存试题 + * @param reqDTO + */ + void save(QuDetailDTO reqDTO); + + /** + * 查找导出列表 + * @param query + * @return + */ + List listForExport(QuQueryReqDTO query); + + /** + * 导入Excel + * @param dtoList + * @return + */ + int importExcel(List dtoList); +} diff --git a/src/main/java/com/guwan/backend/model/qu/service/impl/QuAnswerServiceImpl.java b/src/main/java/com/guwan/backend/model/qu/service/impl/QuAnswerServiceImpl.java new file mode 100644 index 0000000..fc35e7f --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/service/impl/QuAnswerServiceImpl.java @@ -0,0 +1,144 @@ +package com.guwan.backend.model.qu.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.core.utils.BeanMapper; +import com.yf.exam.modules.qu.dto.QuAnswerDTO; +import com.yf.exam.modules.qu.entity.QuAnswer; +import com.yf.exam.modules.qu.mapper.QuAnswerMapper; +import com.yf.exam.modules.qu.service.QuAnswerService; +import com.yf.exam.modules.qu.utils.ImageCheckUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; + +/** +*

+* 语言设置 服务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +@Service +public class QuAnswerServiceImpl extends ServiceImpl implements QuAnswerService { + + @Autowired + private ImageCheckUtils imageCheckUtils; + + @Override + public IPage paging(PagingReqDTO reqDTO) { + + //创建分页对象 + IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); + + //查询条件 + QueryWrapper wrapper = new QueryWrapper<>(); + + //获得数据 + IPage page = this.page(query, wrapper); + //转换结果 + IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); + return pageData; + } + + @Override + public List listAnswerByRandom(String quId) { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(QuAnswer::getQuId, quId); + wrapper.last(" ORDER BY RAND() "); + + return this.list(wrapper); + } + + @Override + public List listByQu(String quId) { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(QuAnswer::getQuId, quId); + + List list = this.list(wrapper); + if(!CollectionUtils.isEmpty(list)){ + return BeanMapper.mapList(list, QuAnswerDTO.class); + } + + return null; + } + + + /** + * 查找已存在的列表 + * @param quId + * @return + */ + public List findExistsList(String quId) { + //返回结果 + List ids = new ArrayList<>(); + + QueryWrapper wrapper = new QueryWrapper(); + wrapper.lambda().eq(QuAnswer::getQuId, quId); + List list = this.list(wrapper); + + if (!CollectionUtils.isEmpty(list)) { + for (QuAnswer item : list) { + ids.add(item.getId()); + } + } + return ids; + } + + @Override + public void saveAll(String quId, List list) { + + //最终要保存的列表 + List saveList = new ArrayList<>(); + + //已存在的标签列表 + List ids = this.findExistsList(quId); + + if(!CollectionUtils.isEmpty(list)){ + for(QuAnswerDTO item: list){ + + // 校验图片地址 + imageCheckUtils.checkImage(item.getImage(), "选项图片地址错误!"); + + //标签ID + String id = item.getId(); + QuAnswer answer = new QuAnswer(); + BeanMapper.copy(item, answer); + answer.setQuId(quId); + + //补全ID避免新增 + if(ids.contains(id)){ + ids.remove(id); + } + + saveList.add(answer); + } + + //保存标签列表 + if(!CollectionUtils.isEmpty(saveList)) { + this.saveOrUpdateBatch(saveList); + } + + //删除已移除 + if(!ids.isEmpty()){ + this.removeByIds(ids); + } + }else{ + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(QuAnswer::getQuId, quId); + this.remove(wrapper); + } + } + + +} diff --git a/src/main/java/com/guwan/backend/model/qu/service/impl/QuRepoServiceImpl.java b/src/main/java/com/guwan/backend/model/qu/service/impl/QuRepoServiceImpl.java new file mode 100644 index 0000000..be8c56b --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/service/impl/QuRepoServiceImpl.java @@ -0,0 +1,175 @@ +package com.guwan.backend.model.qu.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.qu.dto.QuRepoDTO; +import com.yf.exam.modules.qu.dto.request.QuRepoBatchReqDTO; +import com.yf.exam.modules.qu.entity.Qu; +import com.yf.exam.modules.qu.entity.QuRepo; +import com.yf.exam.modules.qu.mapper.QuMapper; +import com.yf.exam.modules.qu.mapper.QuRepoMapper; +import com.yf.exam.modules.qu.service.QuRepoService; +import com.yf.exam.modules.repo.service.RepoService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; + +/** +*

+* 语言设置 服务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ +@Service +public class QuRepoServiceImpl extends ServiceImpl implements QuRepoService { + + + @Autowired + private QuMapper quMapper; + + @Autowired + private RepoService repoService; + + @Override + public IPage paging(PagingReqDTO reqDTO) { + + //创建分页对象 + IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); + + //查询条件 + QueryWrapper wrapper = new QueryWrapper<>(); + + //获得数据 + IPage page = this.page(query, wrapper); + //转换结果 + IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); + return pageData; + } + + @Override + public void saveAll(String quId, Integer quType, List ids) { + // 先删除 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(QuRepo::getQuId, quId); + this.remove(wrapper); + + // 保存全部 + if(!CollectionUtils.isEmpty(ids)){ + List list = new ArrayList<>(); + for(String id: ids){ + QuRepo ref = new QuRepo(); + ref.setQuId(quId); + ref.setRepoId(id); + ref.setQuType(quType); + list.add(ref); + } + this.saveBatch(list); + + + for(String id: ids){ + this.sortRepo(id); + } + } + + + } + + @Override + public List listByQu(String quId) { + // 先删除 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(QuRepo::getQuId, quId); + List list = this.list(wrapper); + List ids = new ArrayList<>(); + if(!CollectionUtils.isEmpty(list)){ + for(QuRepo item: list){ + ids.add(item.getRepoId()); + } + } + return ids; + } + + @Override + public List listByRepo(String repoId, Integer quType, boolean rand) { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda() + .eq(QuRepo::getRepoId, repoId); + + if(quType!=null){ + wrapper.lambda().eq(QuRepo::getQuType, quType); + } + + if(rand){ + wrapper.orderByAsc(" RAND() "); + }else{ + wrapper.lambda().orderByAsc(QuRepo::getSort); + } + + List list = this.list(wrapper); + List ids = new ArrayList<>(); + if(!CollectionUtils.isEmpty(list)){ + for(QuRepo item: list){ + ids.add(item.getQuId()); + } + } + return ids; + } + + @Override + public void batchAction(QuRepoBatchReqDTO reqDTO) { + + // 移除的 + if(reqDTO.getRemove()!=null && reqDTO.getRemove()){ + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda() + .in(QuRepo::getRepoId, reqDTO.getRepoIds()) + .in(QuRepo::getQuId, reqDTO.getQuIds()); + this.remove(wrapper); + }else{ + + // 新增的 + for(String quId : reqDTO.getQuIds()){ + Qu q = quMapper.selectById(quId); + this.saveAll(quId, q.getQuType(), reqDTO.getRepoIds()); + } + } + + for(String id: reqDTO.getRepoIds()){ + this.sortRepo(id); + } + + } + + + /** + * 单个题库进行排序 + * @param repoId + */ + private void sortRepo(String repoId){ + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(QuRepo::getRepoId, repoId); + + List list = this.list(wrapper); + if(CollectionUtils.isEmpty(list)){ + return; + } + + int sort = 1; + for(QuRepo item: list){ + item.setSort(sort); + sort++; + } + this.updateBatchById(list); + } +} diff --git a/src/main/java/com/guwan/backend/model/qu/service/impl/QuServiceImpl.java b/src/main/java/com/guwan/backend/model/qu/service/impl/QuServiceImpl.java new file mode 100644 index 0000000..969c7cf --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/service/impl/QuServiceImpl.java @@ -0,0 +1,277 @@ +package com.guwan.backend.model.qu.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.core.exception.ServiceException; +import com.yf.exam.core.utils.BeanMapper; +import com.yf.exam.modules.qu.dto.QuAnswerDTO; +import com.yf.exam.modules.qu.dto.QuDTO; +import com.yf.exam.modules.qu.dto.export.QuExportDTO; +import com.yf.exam.modules.qu.dto.ext.QuDetailDTO; +import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO; +import com.yf.exam.modules.qu.entity.Qu; +import com.yf.exam.modules.qu.entity.QuAnswer; +import com.yf.exam.modules.qu.entity.QuRepo; +import com.yf.exam.modules.qu.enums.QuType; +import com.yf.exam.modules.qu.mapper.QuMapper; +import com.yf.exam.modules.qu.service.QuAnswerService; +import com.yf.exam.modules.qu.service.QuRepoService; +import com.yf.exam.modules.qu.service.QuService; +import com.yf.exam.modules.qu.utils.ImageCheckUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import java.util.*; + +/** + *

+ * 语言设置 服务实现类 + *

+ * + * @author 聪明笨狗 + * @since 2020-05-25 10:17 + */ +@Service +public class QuServiceImpl extends ServiceImpl implements QuService { + + @Autowired + private QuAnswerService quAnswerService; + + @Autowired + private QuRepoService quRepoService; + + @Autowired + private ImageCheckUtils imageCheckUtils; + + @Override + public IPage paging(PagingReqDTO reqDTO) { + + //创建分页对象 + Page page = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); + + //转换结果 + IPage pageData = baseMapper.paging(page, reqDTO.getParams()); + return pageData; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void delete(List ids) { + // 移除题目 + this.removeByIds(ids); + + // 移除选项 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().in(QuAnswer::getQuId, ids); + quAnswerService.remove(wrapper); + + // 移除题库绑定 + QueryWrapper wrapper1 = new QueryWrapper<>(); + wrapper1.lambda().in(QuRepo::getQuId, ids); + quRepoService.remove(wrapper1); + } + + @Override + public List listByRandom(String repoId, Integer quType, List excludes, Integer size) { + return baseMapper.listByRandom(repoId, quType, excludes, size); + } + + @Override + public QuDetailDTO detail(String id) { + + QuDetailDTO respDTO = new QuDetailDTO(); + Qu qu = this.getById(id); + BeanMapper.copy(qu, respDTO); + + List answerList = quAnswerService.listByQu(id); + respDTO.setAnswerList(answerList); + + List repoIds = quRepoService.listByQu(id); + respDTO.setRepoIds(repoIds); + + return respDTO; + } + + + @Transactional(rollbackFor = Exception.class) + @Override + public void save(QuDetailDTO reqDTO) { + + + // 校验数据 + this.checkData(reqDTO, ""); + + Qu qu = new Qu(); + BeanMapper.copy(reqDTO, qu); + + // 校验图片地址 + imageCheckUtils.checkImage(qu.getImage(), "题干图片地址错误!"); + + // 更新 + this.saveOrUpdate(qu); + + // 保存全部问题 + quAnswerService.saveAll(qu.getId(), reqDTO.getAnswerList()); + + // 保存到题库 + quRepoService.saveAll(qu.getId(), qu.getQuType(), reqDTO.getRepoIds()); + + } + + @Override + public List listForExport(QuQueryReqDTO query) { + return baseMapper.listForExport(query); + } + + @Override + public int importExcel(List dtoList) { + + //根据题目名称分组 + Map> anMap = new HashMap<>(16); + + //题目本体信息 + Map quMap = new HashMap<>(16); + + //数据分组 + for (QuExportDTO item : dtoList) { + + // 空白的ID + if (StringUtils.isEmpty(item.getNo())) { + continue; + } + + Integer key; + //序号 + try { + key = Integer.parseInt(item.getNo()); + } catch (Exception e) { + continue; + } + + //如果已经有题目了,直接处理选项 + if (anMap.containsKey(key)) { + anMap.get(key).add(item); + } else { + //如果没有,将题目内容和选项一起 + List subList = new ArrayList<>(); + subList.add(item); + anMap.put(key, subList); + quMap.put(key, item); + } + } + + int count = 0; + try { + + //循环题目插入 + for (Integer key : quMap.keySet()) { + + QuExportDTO im = quMap.get(key); + + //题目基本信息 + QuDetailDTO qu = new QuDetailDTO(); + qu.setContent(im.getQContent()); + qu.setAnalysis(im.getQAnalysis()); + qu.setQuType(Integer.parseInt(im.getQuType())); + qu.setCreateTime(new Date()); + + //设置回答列表 + List answerList = this.processAnswerList(anMap.get(key)); + //设置题目 + qu.setAnswerList(answerList); + //设置引用题库 + qu.setRepoIds(im.getRepoList()); + // 保存答案 + this.save(qu); + count++; + } + + } catch (ServiceException e) { + e.printStackTrace(); + throw new ServiceException(1, "导入出现问题,行:" + count + "," + e.getMessage()); + } + + return count; + } + + /** + * 处理回答列表 + * + * @param importList + * @return + */ + private List processAnswerList(List importList) { + + List list = new ArrayList<>(16); + for (QuExportDTO item : importList) { + QuAnswerDTO a = new QuAnswerDTO(); + a.setIsRight("1".equals(item.getAIsRight())); + a.setContent(item.getAContent()); + a.setAnalysis(item.getAAnalysis()); + a.setId(""); + list.add(a); + } + return list; + } + + /** + * 校验题目信息 + * + * @param qu + * @param no + * @throws Exception + */ + public void checkData(QuDetailDTO qu, String no) { + + + if (StringUtils.isEmpty(qu.getContent())) { + throw new ServiceException(1, no + "题目内容不能为空!"); + } + + + if (CollectionUtils.isEmpty(qu.getRepoIds())) { + throw new ServiceException(1, no + "至少要选择一个题库!"); + } + + List answers = qu.getAnswerList(); + + + if (CollectionUtils.isEmpty(answers)) { + throw new ServiceException(1, no + "客观题至少要包含一个备选答案!"); + } + + + int trueCount = 0; + for (QuAnswerDTO a : answers) { + + if (a.getIsRight() == null) { + throw new ServiceException(1, no + "必须定义选项是否正确项!"); + } + + if (StringUtils.isEmpty(a.getContent())) { + throw new ServiceException(1, no + "选项内容不为空!"); + } + + if (a.getIsRight()) { + trueCount += 1; + } + } + + if (trueCount == 0) { + throw new ServiceException(1, no + "至少要包含一个正确项!"); + } + + + //单选题 + if (qu.getQuType().equals(QuType.RADIO) && trueCount > 1) { + throw new ServiceException(1, no + "单选题不能包含多个正确项!"); + } + + } +} diff --git a/src/main/java/com/guwan/backend/model/qu/utils/ImageCheckUtils.java b/src/main/java/com/guwan/backend/model/qu/utils/ImageCheckUtils.java new file mode 100644 index 0000000..4fd3ae6 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/qu/utils/ImageCheckUtils.java @@ -0,0 +1,31 @@ +package com.guwan.backend.model.qu.utils; + +import com.yf.exam.ability.upload.config.UploadConfig; +import com.yf.exam.core.exception.ServiceException; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class ImageCheckUtils { + + @Autowired + private UploadConfig conf; + + /** + * 进行图片校验! + * @param image + * @param throwMsg + */ + public void checkImage(String image, String throwMsg) { + + if(StringUtils.isBlank(image)){ + return; + } + + // 校验图片地址 + if(!image.startsWith(conf.getUrl())){ + throw new ServiceException(throwMsg); + } + } +} diff --git a/src/main/java/com/guwan/backend/model/sys/config/controller/SysConfigController.java b/src/main/java/com/guwan/backend/model/sys/config/controller/SysConfigController.java new file mode 100644 index 0000000..f03d57d --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/config/controller/SysConfigController.java @@ -0,0 +1,70 @@ +package com.guwan.backend.model.sys.config.controller; + +import com.yf.exam.core.api.ApiRest; +import com.yf.exam.core.api.controller.BaseController; +import com.yf.exam.core.api.dto.BaseIdRespDTO; +import com.yf.exam.core.utils.BeanMapper; +import com.yf.exam.modules.qu.utils.ImageCheckUtils; +import com.yf.exam.modules.sys.config.dto.SysConfigDTO; +import com.yf.exam.modules.sys.config.entity.SysConfig; +import com.yf.exam.modules.sys.config.service.SysConfigService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.shiro.authz.annotation.RequiresRoles; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** +*

+* 通用配置控制器 +*

+* +* @author 聪明笨狗 +* @since 2020-04-17 09:12 +*/ +@Api(tags={"通用配置"}) +@RestController +@RequestMapping("/exam/api/sys/config") +public class SysConfigController extends BaseController { + + @Autowired + private SysConfigService baseService; + + @Autowired + private ImageCheckUtils imageCheckUtils; + + /** + * 添加或修改 + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "添加或修改") + @RequestMapping(value = "/save", method = { RequestMethod.POST}) + public ApiRest save(@RequestBody SysConfigDTO reqDTO) { + + //复制参数 + SysConfig entity = new SysConfig(); + BeanMapper.copy(reqDTO, entity); + + // 校验图片地址 + imageCheckUtils.checkImage(entity.getBackLogo(), "系统LOGO地址错误!"); + + baseService.saveOrUpdate(entity); + return super.success(new BaseIdRespDTO(entity.getId())); + } + + /** + * 查找详情 + * @return + */ + @ApiOperation(value = "查找详情") + @RequestMapping(value = "/detail", method = { RequestMethod.POST}) + public ApiRest find() { + SysConfigDTO dto = baseService.find(); + return super.success(dto); + } +} diff --git a/src/main/java/com/guwan/backend/model/sys/config/dto/SysConfigDTO.java b/src/main/java/com/guwan/backend/model/sys/config/dto/SysConfigDTO.java new file mode 100644 index 0000000..d0496f2 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/config/dto/SysConfigDTO.java @@ -0,0 +1,39 @@ +package com.guwan.backend.model.sys.config.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** +*

+* 通用配置请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-17 09:12 +*/ +@Data +@ApiModel(value="通用配置", description="通用配置") +public class SysConfigDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "ID", required=true) + private String id; + + @ApiModelProperty(value = "系统名称") + private String siteName; + + @ApiModelProperty(value = "前端LOGO") + private String frontLogo; + + @ApiModelProperty(value = "后台LOGO") + private String backLogo; + + @ApiModelProperty(value = "版权信息") + private String copyRight; + +} diff --git a/src/main/java/com/guwan/backend/model/sys/config/entity/SysConfig.java b/src/main/java/com/guwan/backend/model/sys/config/entity/SysConfig.java new file mode 100644 index 0000000..cddfc42 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/config/entity/SysConfig.java @@ -0,0 +1,53 @@ +package com.guwan.backend.model.sys.config.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** +*

+* 通用配置实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-17 09:12 +*/ +@Data +@TableName("sys_config") +public class SysConfig extends Model { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 系统名称 + */ + @TableField("site_name") + private String siteName; + + /** + * 前端LOGO + */ + @TableField("front_logo") + private String frontLogo; + + /** + * 后台LOGO + */ + @TableField("back_logo") + private String backLogo; + + /** + * 版权信息 + */ + @TableField("copy_right") + private String copyRight; +} diff --git a/src/main/java/com/guwan/backend/model/sys/config/mapper/SysConfigMapper.java b/src/main/java/com/guwan/backend/model/sys/config/mapper/SysConfigMapper.java new file mode 100644 index 0000000..812a982 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/config/mapper/SysConfigMapper.java @@ -0,0 +1,16 @@ +package com.guwan.backend.model.sys.config.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yf.exam.modules.sys.config.entity.SysConfig; + +/** +*

+* 通用配置Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-04-17 09:12 +*/ +public interface SysConfigMapper extends BaseMapper { + +} diff --git a/src/main/java/com/guwan/backend/model/sys/config/service/SysConfigService.java b/src/main/java/com/guwan/backend/model/sys/config/service/SysConfigService.java new file mode 100644 index 0000000..6cc91af --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/config/service/SysConfigService.java @@ -0,0 +1,22 @@ +package com.guwan.backend.model.sys.config.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.yf.exam.modules.sys.config.dto.SysConfigDTO; +import com.yf.exam.modules.sys.config.entity.SysConfig; + +/** +*

+* 通用配置业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-17 09:12 +*/ +public interface SysConfigService extends IService { + + /** + * 查找配置信息 + * @return + */ + SysConfigDTO find(); +} diff --git a/src/main/java/com/guwan/backend/model/sys/config/service/impl/SysConfigServiceImpl.java b/src/main/java/com/guwan/backend/model/sys/config/service/impl/SysConfigServiceImpl.java new file mode 100644 index 0000000..36c0502 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/config/service/impl/SysConfigServiceImpl.java @@ -0,0 +1,34 @@ +package com.guwan.backend.model.sys.config.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.core.utils.BeanMapper; +import com.yf.exam.modules.sys.config.dto.SysConfigDTO; +import com.yf.exam.modules.sys.config.entity.SysConfig; +import com.yf.exam.modules.sys.config.mapper.SysConfigMapper; +import com.yf.exam.modules.sys.config.service.SysConfigService; +import org.springframework.stereotype.Service; + +/** +*

+* 语言设置 服务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-17 09:12 +*/ +@Service +public class SysConfigServiceImpl extends ServiceImpl implements SysConfigService { + + @Override + public SysConfigDTO find() { + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.last(" LIMIT 1"); + + SysConfig entity = this.getOne(wrapper, false); + SysConfigDTO dto = new SysConfigDTO(); + BeanMapper.copy(entity, dto); + return dto; + } +} diff --git a/src/main/java/com/guwan/backend/model/sys/depart/controller/SysDepartController.java b/src/main/java/com/guwan/backend/model/sys/depart/controller/SysDepartController.java new file mode 100644 index 0000000..3450288 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/depart/controller/SysDepartController.java @@ -0,0 +1,150 @@ +package com.guwan.backend.model.sys.depart.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.yf.exam.core.api.ApiRest; +import com.yf.exam.core.api.controller.BaseController; +import com.yf.exam.core.api.dto.BaseIdReqDTO; +import com.yf.exam.core.api.dto.BaseIdsReqDTO; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.core.utils.BeanMapper; +import com.yf.exam.modules.sys.depart.dto.SysDepartDTO; +import com.yf.exam.modules.sys.depart.dto.request.DepartSortReqDTO; +import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO; +import com.yf.exam.modules.sys.depart.entity.SysDepart; +import com.yf.exam.modules.sys.depart.service.SysDepartService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.shiro.authz.annotation.RequiresRoles; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** +*

+* 部门信息控制器 +*

+* +* @author 聪明笨狗 +* @since 2020-09-02 17:25 +*/ +@Api(tags={"部门信息"}) +@RestController +@RequestMapping("/exam/api/sys/depart") +public class SysDepartController extends BaseController { + + @Autowired + private SysDepartService baseService; + + /** + * 添加或修改 + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "添加或修改") + @RequestMapping(value = "/save", method = { RequestMethod.POST}) + public ApiRest save(@RequestBody SysDepartDTO reqDTO) { + baseService.save(reqDTO); + return super.success(); + } + + /** + * 批量删除 + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "批量删除") + @RequestMapping(value = "/delete", method = { RequestMethod.POST}) + public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) { + //根据ID删除 + baseService.removeByIds(reqDTO.getIds()); + return super.success(); + } + + /** + * 查找详情 + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "查找详情") + @RequestMapping(value = "/detail", method = { RequestMethod.POST}) + public ApiRest find(@RequestBody BaseIdReqDTO reqDTO) { + SysDepart entity = baseService.getById(reqDTO.getId()); + SysDepartDTO dto = new SysDepartDTO(); + BeanUtils.copyProperties(entity, dto); + return super.success(dto); + } + + /** + * 分页查找 + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "分页查找") + @RequestMapping(value = "/paging", method = { RequestMethod.POST}) + public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { + + //分页查询并转换 + IPage page = baseService.paging(reqDTO); + + return super.success(page); + } + + /** + * 查找列表,每次最多返回200条数据 + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "查找列表") + @RequestMapping(value = "/list", method = { RequestMethod.POST}) + public ApiRest> list(@RequestBody SysDepartDTO reqDTO) { + + //分页查询并转换 + QueryWrapper wrapper = new QueryWrapper<>(); + + //转换并返回 + List list = baseService.list(wrapper); + + //转换数据 + List dtoList = BeanMapper.mapList(list, SysDepartDTO.class); + + return super.success(dtoList); + } + + + /** + * 树列表 + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "树列表") + @RequestMapping(value = "/tree", method = { RequestMethod.POST}) + public ApiRest> tree() { + List dtoList = baseService.findTree(); + return super.success(dtoList); + } + + + /** + * 分类排序 + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "分类排序") + @RequestMapping(value = "/sort", method = { RequestMethod.POST}) + public ApiRest sort(@RequestBody DepartSortReqDTO reqDTO) { + baseService.sort(reqDTO.getId(), reqDTO.getSort()); + return super.success(); + } +} diff --git a/src/main/java/com/guwan/backend/model/sys/depart/dto/SysDepartDTO.java b/src/main/java/com/guwan/backend/model/sys/depart/dto/SysDepartDTO.java new file mode 100644 index 0000000..148119c --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/depart/dto/SysDepartDTO.java @@ -0,0 +1,42 @@ +package com.guwan.backend.model.sys.depart.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** +*

+* 部门信息数据传输类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-02 17:25 +*/ +@Data +@ApiModel(value="部门信息", description="部门信息") +public class SysDepartDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "ID", required=true) + private String id; + + @ApiModelProperty(value = "1公司2部门", required=true) + private Integer deptType; + + @ApiModelProperty(value = "所属上级", required=true) + private String parentId; + + @ApiModelProperty(value = "部门名称", required=true) + private String deptName; + + @ApiModelProperty(value = "部门编码", required=true) + private String deptCode; + + @ApiModelProperty(value = "排序", required=true) + private Integer sort; + +} diff --git a/src/main/java/com/guwan/backend/model/sys/depart/dto/request/DepartSortReqDTO.java b/src/main/java/com/guwan/backend/model/sys/depart/dto/request/DepartSortReqDTO.java new file mode 100644 index 0000000..6e5def3 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/depart/dto/request/DepartSortReqDTO.java @@ -0,0 +1,28 @@ +package com.guwan.backend.model.sys.depart.dto.request; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** +*

+* 部门排序请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-03-14 10:37 +*/ +@Data +@ApiModel(value="部门排序请求类", description="部门排序请求类") +public class DepartSortReqDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "分类ID") + private String id; + + @ApiModelProperty(value = "排序,0下降,1上升") + private Integer sort; +} diff --git a/src/main/java/com/guwan/backend/model/sys/depart/dto/response/SysDepartTreeDTO.java b/src/main/java/com/guwan/backend/model/sys/depart/dto/response/SysDepartTreeDTO.java new file mode 100644 index 0000000..c6215d1 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/depart/dto/response/SysDepartTreeDTO.java @@ -0,0 +1,28 @@ +package com.guwan.backend.model.sys.depart.dto.response; + +import com.yf.exam.modules.sys.depart.dto.SysDepartDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** +*

+* 部门树结构响应类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-02 17:25 +*/ +@Data +@ApiModel(value="部门树结构响应类", description="部门树结构响应类") +public class SysDepartTreeDTO extends SysDepartDTO { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "子列表", required=true) + private List children; + + +} diff --git a/src/main/java/com/guwan/backend/model/sys/depart/entity/SysDepart.java b/src/main/java/com/guwan/backend/model/sys/depart/entity/SysDepart.java new file mode 100644 index 0000000..4c3aa37 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/depart/entity/SysDepart.java @@ -0,0 +1,59 @@ +package com.guwan.backend.model.sys.depart.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** +*

+* 部门信息实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-02 17:25 +*/ +@Data +@TableName("sys_depart") +public class SysDepart extends Model { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 1公司2部门 + */ + @TableField("dept_type") + private Integer deptType; + + /** + * 所属上级 + */ + @TableField("parent_id") + private String parentId; + + /** + * 部门名称 + */ + @TableField("dept_name") + private String deptName; + + /** + * 部门编码 + */ + @TableField("dept_code") + private String deptCode; + + /** + * 排序 + */ + private Integer sort; + +} diff --git a/src/main/java/com/guwan/backend/model/sys/depart/mapper/SysDepartMapper.java b/src/main/java/com/guwan/backend/model/sys/depart/mapper/SysDepartMapper.java new file mode 100644 index 0000000..c987057 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/depart/mapper/SysDepartMapper.java @@ -0,0 +1,28 @@ +package com.guwan.backend.model.sys.depart.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.yf.exam.modules.sys.depart.dto.SysDepartDTO; +import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO; +import com.yf.exam.modules.sys.depart.entity.SysDepart; +import org.apache.ibatis.annotations.Param; + +/** +*

+* 部门信息Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-09-02 17:25 +*/ +public interface SysDepartMapper extends BaseMapper { + + /** + * 部门树分页 + * @param page + * @param query + * @return + */ + IPage paging(Page page, @Param("query") SysDepartDTO query); +} diff --git a/src/main/java/com/guwan/backend/model/sys/depart/service/SysDepartService.java b/src/main/java/com/guwan/backend/model/sys/depart/service/SysDepartService.java new file mode 100644 index 0000000..19467f9 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/depart/service/SysDepartService.java @@ -0,0 +1,62 @@ +package com.guwan.backend.model.sys.depart.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.sys.depart.dto.SysDepartDTO; +import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO; +import com.yf.exam.modules.sys.depart.entity.SysDepart; + +import java.util.List; + +/** +*

+* 部门信息业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-02 17:25 +*/ +public interface SysDepartService extends IService { + + /** + * 保存 + * @param reqDTO + */ + void save(SysDepartDTO reqDTO); + + /** + * 分页查询数据 + * @param reqDTO + * @return + */ + IPage paging(PagingReqDTO reqDTO); + + /** + * 查找部门树结构 + * @return + */ + List findTree(); + + /** + * 查找部门树 + * @param ids + * @return + */ + List findTree(List ids); + + /** + * 排序 + * @param id + * @param sort + */ + void sort(String id, Integer sort); + + + /** + * 获取某个部门ID下的所有子部门ID + * @param id + * @return + */ + List listAllSubIds( String id); +} diff --git a/src/main/java/com/guwan/backend/model/sys/depart/service/impl/SysDepartServiceImpl.java b/src/main/java/com/guwan/backend/model/sys/depart/service/impl/SysDepartServiceImpl.java new file mode 100644 index 0000000..1ded455 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/depart/service/impl/SysDepartServiceImpl.java @@ -0,0 +1,288 @@ +package com.guwan.backend.model.sys.depart.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.core.utils.BeanMapper; +import com.yf.exam.modules.sys.depart.dto.SysDepartDTO; +import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO; +import com.yf.exam.modules.sys.depart.entity.SysDepart; +import com.yf.exam.modules.sys.depart.mapper.SysDepartMapper; +import com.yf.exam.modules.sys.depart.service.SysDepartService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** +*

+* 部门信息业务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-02 17:25 +*/ +@Service +public class SysDepartServiceImpl extends ServiceImpl implements SysDepartService { + + + /** + * 0标识为顶级分类 + */ + private static final String ROOT_TAG = "0"; + + + @Override + public void save(SysDepartDTO reqDTO) { + + if(StringUtils.isBlank(reqDTO.getId())) { + this.fillCode(reqDTO); + }else{ + reqDTO.setSort(null); + reqDTO.setDeptCode(null); + } + + SysDepart entity = new SysDepart(); + BeanMapper.copy(reqDTO, entity); + this.saveOrUpdate(entity); + } + + @Override + public IPage paging(PagingReqDTO reqDTO) { + + // 创建分页对象 + Page query = new Page(reqDTO.getCurrent(), reqDTO.getSize()); + + // 请求参数 + SysDepartDTO params = reqDTO.getParams(); + + //转换结果 + IPage pageData = baseMapper.paging(query, params); + + return pageData; + } + + + @Override + public List findTree() { + return this.findTree(null); + } + + @Override + public List findTree(List ids) { + + + QueryWrapper wrapper = new QueryWrapper(); + wrapper.lambda().orderByAsc(SysDepart::getSort); + + if(!CollectionUtils.isEmpty(ids)){ + + List fullIds = new ArrayList<>(); + for(String id: ids){ + this.cycleAllParent(fullIds, id); + } + + if(!CollectionUtils.isEmpty(fullIds)){ + wrapper.lambda().in(SysDepart::getId, fullIds); + } + } + + //全部列表 + List list = this.list(wrapper); + List dtoList = BeanMapper.mapList(list, SysDepartTreeDTO.class); + + //子结构的列表 + Map> map = new HashMap<>(16); + + for(SysDepartTreeDTO item: dtoList){ + + //如果存在 + if(map.containsKey(item.getParentId())){ + map.get(item.getParentId()).add(item); + continue; + } + + //增加新的结构 + List a = new ArrayList<>(); + a.add(item); + map.put(item.getParentId(), a); + } + + //注意,第0级为顶级的 + List topList = map.get(ROOT_TAG); + if(!CollectionUtils.isEmpty(topList)){ + for(SysDepartTreeDTO item: topList){ + this.fillChildren(map, item); + } + } + + return topList; + } + + @Override + public void sort(String id, Integer sort) { + + SysDepart depart = this.getById(id); + SysDepart exchange = null; + + QueryWrapper wrapper = new QueryWrapper<>(); + // 同级排序 + wrapper.lambda() + .eq(SysDepart::getParentId, depart.getParentId()); + wrapper.last("LIMIT 1"); + + // 上升 + if(sort == 0){ + // 同级排序 + wrapper.lambda() + .lt(SysDepart::getSort, depart.getSort()) + .orderByDesc(SysDepart::getSort); + exchange = this.getOne(wrapper, false); + } + + // 下降 + if(sort == 1){ + // 同级排序 + wrapper.lambda() + .gt(SysDepart::getSort, depart.getSort()) + .orderByAsc(SysDepart::getSort); + exchange = this.getOne(wrapper, false); + } + + + if(exchange!=null) { + SysDepart a = new SysDepart(); + a.setId(id); + a.setSort(exchange.getSort()); + SysDepart b = new SysDepart(); + b.setId(exchange.getId()); + b.setSort(depart.getSort()); + this.updateById(a); + this.updateById(b); + } + } + + /** + * 获取部门编号 + * @param reqDTO + * @return + */ + private void fillCode(SysDepartDTO reqDTO){ + + // 前缀 + String code = ""; + + if(StringUtils.isNotBlank(reqDTO.getParentId()) + && !ROOT_TAG.equals(reqDTO.getParentId())){ + SysDepart parent = this.getById(reqDTO.getParentId()); + code = parent.getDeptCode(); + } + + QueryWrapper wrapper = new QueryWrapper<>(); + + // 同级排序 + wrapper.lambda() + .eq(SysDepart::getParentId, reqDTO.getParentId()) + .orderByDesc(SysDepart::getSort); + wrapper.last("LIMIT 1"); + SysDepart depart = this.getOne(wrapper, false); + + if(depart !=null){ + code += this.formatCode(depart.getSort()+1); + reqDTO.setSort(depart.getSort()+1); + }else{ + code += this.formatCode(1); + reqDTO.setSort(1); + } + + reqDTO.setDeptCode(code); + } + + /** + * 根式化加0 + * @param sort + * @return + */ + private String formatCode(Integer sort){ + if(sort < 10){ + return "A0"+sort; + } + return "A"+sort; + } + + /** + * 递归去做填充数据 + * @param map + * @param item + */ + private void fillChildren(Map> map, SysDepartTreeDTO item){ + + //设置子类 + if(map.containsKey(item.getId())){ + + List children = map.get(item.getId()); + if(!CollectionUtils.isEmpty(children)){ + for(SysDepartTreeDTO sub: children){ + this.fillChildren(map, sub); + } + } + item.setChildren(children); + } + } + + + @Override + public List listAllSubIds( String id){ + + List ids = new ArrayList<>(); + this.cycleAllSubs(ids, id); + return ids; + } + + + /** + * 递归所有子级别ID + * @param list + * @param id + */ + private void cycleAllSubs(List list, String id){ + + // 添加ID + list.add(id); + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda() + .eq(SysDepart::getParentId, id) + .orderByDesc(SysDepart::getSort); + List subList = this.list(wrapper); + if(!CollectionUtils.isEmpty(subList)){ + for(SysDepart item: subList){ + this.cycleAllSubs(list, item.getId()); + } + } + } + + /** + * 递归所有子级别ID + * @param list + * @param id + */ + private void cycleAllParent(List list, String id){ + + // 往上递归获得父类 + list.add(id); + SysDepart depart = this.getById(id); + + if(StringUtils.isNotBlank(depart.getParentId()) + && !ROOT_TAG.equals(depart.getParentId())){ + this.cycleAllParent(list, depart.getParentId()); + } + + } +} diff --git a/src/main/java/com/guwan/backend/model/sys/system/mapper/SysDictMapper.java b/src/main/java/com/guwan/backend/model/sys/system/mapper/SysDictMapper.java new file mode 100644 index 0000000..d9dd5cc --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/system/mapper/SysDictMapper.java @@ -0,0 +1,29 @@ +package com.guwan.backend.model.sys.system.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +/** +*

+* 机主信息Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-08-22 13:46 +*/ +@Mapper +public interface SysDictMapper { + + /** + * 查找数据字典 + * @param table + * @param text + * @param key + * @param value + * @return + */ + String findDict(@Param("table") String table, + @Param("text") String text, + @Param("key") String key, + @Param("value") String value); +} diff --git a/src/main/java/com/guwan/backend/model/sys/system/service/SysDictService.java b/src/main/java/com/guwan/backend/model/sys/system/service/SysDictService.java new file mode 100644 index 0000000..02093d9 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/system/service/SysDictService.java @@ -0,0 +1,21 @@ +package com.guwan.backend.model.sys.system.service; + +/** + * 数据字典工具类 + * @author bool + */ +public interface SysDictService { + + /** + * 查找数据字典 + * @param table + * @param text + * @param key + * @param value + * @return + */ + String findDict(String table, + String text, + String key, + String value); +} diff --git a/src/main/java/com/guwan/backend/model/sys/system/service/impl/SysDictServiceImpl.java b/src/main/java/com/guwan/backend/model/sys/system/service/impl/SysDictServiceImpl.java new file mode 100644 index 0000000..d200625 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/system/service/impl/SysDictServiceImpl.java @@ -0,0 +1,21 @@ +package com.guwan.backend.model.sys.system.service.impl; + +import com.yf.exam.modules.sys.system.mapper.SysDictMapper; +import com.yf.exam.modules.sys.system.service.SysDictService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author bool + */ +@Service +public class SysDictServiceImpl implements SysDictService { + + @Autowired + private SysDictMapper sysDictMapper; + + @Override + public String findDict(String table, String text, String key, String value) { + return sysDictMapper.findDict(table, text, key, value); + } +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/controller/SysRoleController.java b/src/main/java/com/guwan/backend/model/sys/user/controller/SysRoleController.java new file mode 100644 index 0000000..280cd04 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/controller/SysRoleController.java @@ -0,0 +1,77 @@ +package com.guwan.backend.model.sys.user.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.yf.exam.core.api.ApiRest; +import com.yf.exam.core.api.controller.BaseController; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.core.utils.BeanMapper; +import com.yf.exam.modules.sys.user.dto.SysRoleDTO; +import com.yf.exam.modules.sys.user.entity.SysRole; +import com.yf.exam.modules.sys.user.service.SysRoleService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.shiro.authz.annotation.RequiresRoles; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + *

+ * 管理用户控制器 + *

+ * + * @author 聪明笨狗 + * @since 2020-04-13 16:57 + */ +@Api(tags = {"管理用户"}) +@RestController +@RequestMapping("/exam/api/sys/role") +public class SysRoleController extends BaseController { + + @Autowired + private SysRoleService baseService; + + + + + /** + * 分页查找 + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "分页查找") + @RequestMapping(value = "/paging", method = { RequestMethod.POST}) + public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { + + //分页查询并转换 + IPage page = baseService.paging(reqDTO); + return super.success(page); + } + + /** + * 查找列表,每次最多返回200条数据 + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "查找列表") + @RequestMapping(value = "/list", method = { RequestMethod.POST}) + public ApiRest> list() { + + //分页查询并转换 + QueryWrapper wrapper = new QueryWrapper<>(); + + //转换并返回 + List list = baseService.list(wrapper); + + //转换数据 + List dtoList = BeanMapper.mapList(list, SysRoleDTO.class); + + return super.success(dtoList); + } +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/controller/SysUserController.java b/src/main/java/com/guwan/backend/model/sys/user/controller/SysUserController.java new file mode 100644 index 0000000..c84df4c --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/controller/SysUserController.java @@ -0,0 +1,177 @@ +package com.guwan.backend.model.sys.user.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.yf.exam.core.api.ApiRest; +import com.yf.exam.core.api.controller.BaseController; +import com.yf.exam.core.api.dto.BaseIdsReqDTO; +import com.yf.exam.core.api.dto.BaseStateReqDTO; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.sys.user.dto.SysUserDTO; +import com.yf.exam.modules.sys.user.dto.request.SysUserLoginReqDTO; +import com.yf.exam.modules.sys.user.dto.request.SysUserSaveReqDTO; +import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; +import com.yf.exam.modules.sys.user.entity.SysUser; +import com.yf.exam.modules.sys.user.service.SysUserService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.shiro.authz.annotation.RequiresRoles; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; + +/** + *

+ * 管理用户控制器 + *

+ * + * @author 聪明笨狗 + * @since 2020-04-13 16:57 + */ +@Api(tags = {"管理用户"}) +@RestController +@RequestMapping("/exam/api/sys/user") +public class SysUserController extends BaseController { + + @Autowired + private SysUserService baseService; + + /** + * 用户登录 + * @return + */ + @CrossOrigin + @ApiOperation(value = "用户登录") + @RequestMapping(value = "/login", method = {RequestMethod.POST}) + public ApiRest login(@RequestBody SysUserLoginReqDTO reqDTO) { + SysUserLoginDTO respDTO = baseService.login(reqDTO.getUsername(), reqDTO.getPassword()); + return super.success(respDTO); + } + + /** + * 用户登录 + * @return + */ + @CrossOrigin + @ApiOperation(value = "用户登录") + @RequestMapping(value = "/logout", method = {RequestMethod.POST}) + public ApiRest logout(HttpServletRequest request) { + String token = request.getHeader("token"); + System.out.println("+++++当前会话为:"+token); + baseService.logout(token); + return super.success(); + } + + /** + * 获取会话 + * @return + */ + @ApiOperation(value = "获取会话") + @RequestMapping(value = "/info", method = {RequestMethod.POST}) + public ApiRest info(@RequestParam("token") String token) { + SysUserLoginDTO respDTO = baseService.token(token); + return success(respDTO); + } + + /** + * 修改用户资料 + * @return + */ + @ApiOperation(value = "修改用户资料") + @RequestMapping(value = "/update", method = {RequestMethod.POST}) + public ApiRest update(@RequestBody SysUserDTO reqDTO) { + baseService.update(reqDTO); + return success(); + } + + + /** + * 保存或修改系统用户 + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "保存或修改") + @RequestMapping(value = "/save", method = {RequestMethod.POST}) + public ApiRest save(@RequestBody SysUserSaveReqDTO reqDTO) { + baseService.save(reqDTO); + return success(); + } + + + /** + * 批量删除 + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "批量删除") + @RequestMapping(value = "/delete", method = { RequestMethod.POST}) + public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) { + //根据ID删除 + baseService.removeByIds(reqDTO.getIds()); + return super.success(); + } + + /** + * 分页查找 + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "分页查找") + @RequestMapping(value = "/paging", method = { RequestMethod.POST}) + public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { + + //分页查询并转换 + IPage page = baseService.paging(reqDTO); + return super.success(page); + } + + /** + * 修改状态 + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "修改状态") + @RequestMapping(value = "/state", method = { RequestMethod.POST}) + public ApiRest state(@RequestBody BaseStateReqDTO reqDTO) { + + // 条件 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda() + .in(SysUser::getId, reqDTO.getIds()) + .ne(SysUser::getUserName, "admin"); + + + SysUser record = new SysUser(); + record.setState(reqDTO.getState()); + baseService.update(record, wrapper); + + return super.success(); + } + + + /** + * 保存或修改系统用户 + * @return + */ + @ApiOperation(value = "学员注册") + @RequestMapping(value = "/reg", method = {RequestMethod.POST}) + public ApiRest reg(@RequestBody SysUserDTO reqDTO) { + SysUserLoginDTO respDTO = baseService.reg(reqDTO); + return success(respDTO); + } + + /** + * 快速注册,如果手机号存在则登录,不存在就注册 + * @return + */ + @ApiOperation(value = "快速注册") + @RequestMapping(value = "/quick-reg", method = {RequestMethod.POST}) + public ApiRest quick(@RequestBody SysUserDTO reqDTO) { + SysUserLoginDTO respDTO = baseService.quickReg(reqDTO); + return success(respDTO); + } +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/dto/SysRoleDTO.java b/src/main/java/com/guwan/backend/model/sys/user/dto/SysRoleDTO.java new file mode 100644 index 0000000..c9cd869 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/dto/SysRoleDTO.java @@ -0,0 +1,30 @@ +package com.guwan.backend.model.sys.user.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** +*

+* 角色请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +@Data +@ApiModel(value="角色", description="角色") +public class SysRoleDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "角色ID", required=true) + private String id; + + @ApiModelProperty(value = "角色名称", required=true) + private String roleName; + +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/dto/SysUserDTO.java b/src/main/java/com/guwan/backend/model/sys/user/dto/SysUserDTO.java new file mode 100644 index 0000000..30a2d7b --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/dto/SysUserDTO.java @@ -0,0 +1,55 @@ +package com.guwan.backend.model.sys.user.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** +*

+* 管理用户请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +@Data +@ApiModel(value="管理用户", description="管理用户") +public class SysUserDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "ID", required=true) + private String id; + + @ApiModelProperty(value = "用户名", required=true) + private String userName; + + @ApiModelProperty(value = "真实姓名", required=true) + private String realName; + + @ApiModelProperty(value = "密码", required=true) + private String password; + + @ApiModelProperty(value = "密码盐", required=true) + private String salt; + + @ApiModelProperty(value = "角色列表", required=true) + private String roleIds; + + @ApiModelProperty(value = "部门ID", required=true) + private String departId; + + @ApiModelProperty(value = "创建时间", required=true) + private Date createTime; + + @ApiModelProperty(value = "更新时间", required=true) + private Date updateTime; + + @ApiModelProperty(value = "状态", required=true) + private Integer state; + +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/dto/SysUserRoleDTO.java b/src/main/java/com/guwan/backend/model/sys/user/dto/SysUserRoleDTO.java new file mode 100644 index 0000000..7783142 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/dto/SysUserRoleDTO.java @@ -0,0 +1,33 @@ +package com.guwan.backend.model.sys.user.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** +*

+* 用户角色请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +@Data +@ApiModel(value="用户角色", description="用户角色") +public class SysUserRoleDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "ID", required=true) + private String id; + + @ApiModelProperty(value = "用户ID", required=true) + private String userId; + + @ApiModelProperty(value = "角色ID", required=true) + private String roleId; + +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/dto/request/SysUserLoginReqDTO.java b/src/main/java/com/guwan/backend/model/sys/user/dto/request/SysUserLoginReqDTO.java new file mode 100644 index 0000000..3b7611c --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/dto/request/SysUserLoginReqDTO.java @@ -0,0 +1,29 @@ +package com.guwan.backend.model.sys.user.dto.request; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** +*

+* 管理员登录请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +@Data +@ApiModel(value="管理员登录请求类", description="管理员登录请求类") +public class SysUserLoginReqDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "用户名", required=true) + private String username; + + @ApiModelProperty(value = "密码", required=true) + private String password; + +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/dto/request/SysUserSaveReqDTO.java b/src/main/java/com/guwan/backend/model/sys/user/dto/request/SysUserSaveReqDTO.java new file mode 100644 index 0000000..14acf71 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/dto/request/SysUserSaveReqDTO.java @@ -0,0 +1,43 @@ +package com.guwan.backend.model.sys.user.dto.request; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** +*

+* 管理员登录请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +@Data +@ApiModel(value="管理员保存请求类", description="管理员保存请求类") +public class SysUserSaveReqDTO implements Serializable { + + @ApiModelProperty(value = "ID", required=true) + private String id; + + @ApiModelProperty(value = "用户名", required=true) + private String userName; + + @ApiModelProperty(value = "头像", required=true) + private String avatar; + + @ApiModelProperty(value = "真实姓名", required=true) + private String realName; + + @ApiModelProperty(value = "密码", required=true) + private String password; + + @ApiModelProperty(value = "部门", required=true) + private String departId; + + @ApiModelProperty(value = "角色列表", required=true) + private List roles; + +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/dto/request/SysUserTokenReqDTO.java b/src/main/java/com/guwan/backend/model/sys/user/dto/request/SysUserTokenReqDTO.java new file mode 100644 index 0000000..6673b15 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/dto/request/SysUserTokenReqDTO.java @@ -0,0 +1,26 @@ +package com.guwan.backend.model.sys.user.dto.request; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** +*

+* 会话检查请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +@Data +@ApiModel(value="会话检查请求类", description="会话检查请求类") +public class SysUserTokenReqDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "用户名", required=true) + private String token; + +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/dto/response/SysUserLoginDTO.java b/src/main/java/com/guwan/backend/model/sys/user/dto/response/SysUserLoginDTO.java new file mode 100644 index 0000000..1e4e0d4 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/dto/response/SysUserLoginDTO.java @@ -0,0 +1,55 @@ +package com.guwan.backend.model.sys.user.dto.response; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** +*

+* 管理用户请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +@Data +@ApiModel(value="管理用户登录响应类", description="管理用户登录响应类") +public class SysUserLoginDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "ID", required=true) + private String id; + + @ApiModelProperty(value = "用户名", required=true) + private String userName; + + @ApiModelProperty(value = "真实姓名", required=true) + private String realName; + + @ApiModelProperty(value = "角色列表", required=true) + private String roleIds; + + @ApiModelProperty(value = "部门ID", required=true) + private String departId; + + @ApiModelProperty(value = "创建时间", required=true) + private Date createTime; + + @ApiModelProperty(value = "更新时间", required=true) + private Date updateTime; + + @ApiModelProperty(value = "状态", required=true) + private Integer state; + + @ApiModelProperty(value = "角色列表", required=true) + private List roles; + + @ApiModelProperty(value = "登录令牌", required=true) + private String token; + +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/entity/SysRole.java b/src/main/java/com/guwan/backend/model/sys/user/entity/SysRole.java new file mode 100644 index 0000000..7290769 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/entity/SysRole.java @@ -0,0 +1,36 @@ +package com.guwan.backend.model.sys.user.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** +*

+* 角色实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +@Data +@TableName("sys_role") +public class SysRole extends Model { + + private static final long serialVersionUID = 1L; + + /** + * 角色ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 角色名称 + */ + @TableField("role_name") + private String roleName; + +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/entity/SysUser.java b/src/main/java/com/guwan/backend/model/sys/user/entity/SysUser.java new file mode 100644 index 0000000..67f24d6 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/entity/SysUser.java @@ -0,0 +1,83 @@ +package com.guwan.backend.model.sys.user.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +import java.util.Date; + +/** +*

+* 管理用户实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +@Data +@TableName("sys_user") +public class SysUser extends Model { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 用户名 + */ + @TableField("user_name") + private String userName; + + /** + * 真实姓名 + */ + @TableField("real_name") + private String realName; + + /** + * 密码 + */ + private String password; + + /** + * 密码盐 + */ + private String salt; + + /** + * 角色列表 + */ + @TableField("role_ids") + private String roleIds; + + /** + * 部门ID + */ + @TableField("depart_id") + private String departId; + + /** + * 创建时间 + */ + @TableField("create_time") + private Date createTime; + + /** + * 更新时间 + */ + @TableField("update_time") + private Date updateTime; + + /** + * 状态 + */ + private Integer state; + +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/entity/SysUserRole.java b/src/main/java/com/guwan/backend/model/sys/user/entity/SysUserRole.java new file mode 100644 index 0000000..1621426 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/entity/SysUserRole.java @@ -0,0 +1,42 @@ +package com.guwan.backend.model.sys.user.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +/** +*

+* 用户角色实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +@Data +@TableName("sys_user_role") +public class SysUserRole extends Model { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 用户ID + */ + @TableField("user_id") + private String userId; + + /** + * 角色ID + */ + @TableField("role_id") + private String roleId; + +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/mapper/SysRoleMapper.java b/src/main/java/com/guwan/backend/model/sys/user/mapper/SysRoleMapper.java new file mode 100644 index 0000000..cce0666 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/mapper/SysRoleMapper.java @@ -0,0 +1,15 @@ +package com.guwan.backend.model.sys.user.mapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yf.exam.modules.sys.user.entity.SysRole; + +/** +*

+* 角色Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +public interface SysRoleMapper extends BaseMapper { + +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/mapper/SysUserMapper.java b/src/main/java/com/guwan/backend/model/sys/user/mapper/SysUserMapper.java new file mode 100644 index 0000000..0d176f8 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/mapper/SysUserMapper.java @@ -0,0 +1,16 @@ +package com.guwan.backend.model.sys.user.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yf.exam.modules.sys.user.entity.SysUser; + +/** +*

+* 管理用户Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +public interface SysUserMapper extends BaseMapper { + +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/mapper/SysUserRoleMapper.java b/src/main/java/com/guwan/backend/model/sys/user/mapper/SysUserRoleMapper.java new file mode 100644 index 0000000..a438daa --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/mapper/SysUserRoleMapper.java @@ -0,0 +1,16 @@ +package com.guwan.backend.model.sys.user.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yf.exam.modules.sys.user.entity.SysUserRole; + +/** +*

+* 用户角色Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +public interface SysUserRoleMapper extends BaseMapper { + +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/service/SysRoleService.java b/src/main/java/com/guwan/backend/model/sys/user/service/SysRoleService.java new file mode 100644 index 0000000..3f0d8b5 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/service/SysRoleService.java @@ -0,0 +1,25 @@ +package com.guwan.backend.model.sys.user.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.sys.user.dto.SysRoleDTO; +import com.yf.exam.modules.sys.user.entity.SysRole; + +/** +*

+* 角色业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +public interface SysRoleService extends IService { + + /** + * 分页查询数据 + * @param reqDTO + * @return + */ + IPage paging(PagingReqDTO reqDTO); +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/service/SysUserRoleService.java b/src/main/java/com/guwan/backend/model/sys/user/service/SysUserRoleService.java new file mode 100644 index 0000000..3bc4c97 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/service/SysUserRoleService.java @@ -0,0 +1,61 @@ +package com.guwan.backend.model.sys.user.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.sys.user.dto.SysUserRoleDTO; +import com.yf.exam.modules.sys.user.entity.SysUserRole; + +import java.util.List; + +/** +*

+* 用户角色业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +public interface SysUserRoleService extends IService { + + /** + * 分页查询数据 + * @param reqDTO + * @return + */ + IPage paging(PagingReqDTO reqDTO); + + /** + * 查找用户角色列表 + * @param userId + * @return + */ + List listRoles(String userId); + + /** + * 保存全部角色 + * @param userId + * @param ids + * @return + */ + String saveRoles(String userId, List ids); + + /** + * 是否学生 + * @param userId + * @return + */ + boolean isStudent(String userId); + + /** + * 是否老师 + */ + boolean isTeacher(String userId); + + /** + * 是否管理 + * @param userId + * @return + */ + boolean isAdmin(String userId); +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/service/SysUserService.java b/src/main/java/com/guwan/backend/model/sys/user/service/SysUserService.java new file mode 100644 index 0000000..f1a5f73 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/service/SysUserService.java @@ -0,0 +1,72 @@ +package com.guwan.backend.model.sys.user.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.sys.user.dto.SysUserDTO; +import com.yf.exam.modules.sys.user.dto.request.SysUserSaveReqDTO; +import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; +import com.yf.exam.modules.sys.user.entity.SysUser; + +/** +*

+* 管理用户业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +public interface SysUserService extends IService { + + /** + * 分页查询数据 + * @param reqDTO + * @return + */ + IPage paging(PagingReqDTO reqDTO); + + /** + * 登录 + * @param userName + * @param password + * @return + */ + SysUserLoginDTO login(String userName, String password); + + /** + * 获取管理会话 + * @param token + * @return + */ + SysUserLoginDTO token(String token); + + /** + * 退出登录 + * @param token + */ + void logout(String token); + + /** + * 修改用户资料 + * @param reqDTO + */ + void update(SysUserDTO reqDTO); + + /** + * 保存添加系统用户 + * @param reqDTO + */ + void save(SysUserSaveReqDTO reqDTO); + + /** + * 用户注册 + * @param reqDTO + */ + SysUserLoginDTO reg(SysUserDTO reqDTO); + + /** + * 快速注册 + * @param reqDTO + */ + SysUserLoginDTO quickReg(SysUserDTO reqDTO); +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/service/impl/SysRoleServiceImpl.java b/src/main/java/com/guwan/backend/model/sys/user/service/impl/SysRoleServiceImpl.java new file mode 100644 index 0000000..1263789 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/service/impl/SysRoleServiceImpl.java @@ -0,0 +1,42 @@ +package com.guwan.backend.model.sys.user.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.sys.user.dto.SysRoleDTO; +import com.yf.exam.modules.sys.user.entity.SysRole; +import com.yf.exam.modules.sys.user.mapper.SysRoleMapper; +import com.yf.exam.modules.sys.user.service.SysRoleService; +import org.springframework.stereotype.Service; + +/** +*

+* 语言设置 服务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +@Service +public class SysRoleServiceImpl extends ServiceImpl implements SysRoleService { + + @Override + public IPage paging(PagingReqDTO reqDTO) { + + //创建分页对象 + IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); + + //查询条件 + QueryWrapper wrapper = new QueryWrapper<>(); + + //获得数据 + IPage page = this.page(query, wrapper); + //转换结果 + IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); + return pageData; + } +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/service/impl/SysUserRoleServiceImpl.java b/src/main/java/com/guwan/backend/model/sys/user/service/impl/SysUserRoleServiceImpl.java new file mode 100644 index 0000000..40a9507 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/service/impl/SysUserRoleServiceImpl.java @@ -0,0 +1,128 @@ +package com.guwan.backend.model.sys.user.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.sys.user.dto.SysUserRoleDTO; +import com.yf.exam.modules.sys.user.entity.SysUserRole; +import com.yf.exam.modules.sys.user.mapper.SysUserRoleMapper; +import com.yf.exam.modules.sys.user.service.SysUserRoleService; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +/** +*

+* 语言设置 服务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +@Service +public class SysUserRoleServiceImpl extends ServiceImpl implements SysUserRoleService { + + @Override + public IPage paging(PagingReqDTO reqDTO) { + + //创建分页对象 + IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); + + //查询条件 + QueryWrapper wrapper = new QueryWrapper<>(); + + //获得数据 + IPage page = this.page(query, wrapper); + //转换结果 + IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); + return pageData; + } + + @Override + public List listRoles(String userId) { + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(SysUserRole::getUserId, userId); + + List list = this.list(wrapper); + List roles = new ArrayList<>(); + if(!CollectionUtils.isEmpty(list)){ + for(SysUserRole item: list){ + roles.add(item.getRoleId()); + } + } + + return roles; + } + + @Override + public String saveRoles(String userId, List ids) { + + // 删除全部角色 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(SysUserRole::getUserId, userId); + this.remove(wrapper); + + + if(!CollectionUtils.isEmpty(ids)){ + + List list = new ArrayList<>(); + String roleIds = null; + + for(String item: ids){ + SysUserRole role = new SysUserRole(); + role.setRoleId(item); + role.setUserId(userId); + list.add(role); + if(StringUtils.isEmpty(roleIds)){ + roleIds = item; + }else{ + roleIds+=","+item; + } + } + + this.saveBatch(list); + return roleIds; + } + + return ""; + } + + @Override + public boolean isStudent(String userId) { + + // 学生角色 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(SysUserRole::getUserId, userId) + .eq(SysUserRole::getRoleId, "student"); + + return this.count(wrapper) > 0; + } + + @Override + public boolean isTeacher(String userId) { + // 学生角色 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(SysUserRole::getUserId, userId) + .eq(SysUserRole::getRoleId, "teacher"); + + return this.count(wrapper) > 0; + } + + @Override + public boolean isAdmin(String userId) { + // 学生角色 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(SysUserRole::getUserId, userId) + .eq(SysUserRole::getRoleId, "sa"); + + return this.count(wrapper) > 0; + } +} diff --git a/src/main/java/com/guwan/backend/model/sys/user/service/impl/SysUserServiceImpl.java b/src/main/java/com/guwan/backend/model/sys/user/service/impl/SysUserServiceImpl.java new file mode 100644 index 0000000..e40fed3 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/sys/user/service/impl/SysUserServiceImpl.java @@ -0,0 +1,253 @@ +package com.guwan.backend.model.sys.user.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.ability.shiro.jwt.JwtUtils; +import com.yf.exam.core.api.ApiError; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.core.enums.CommonState; +import com.yf.exam.core.exception.ServiceException; +import com.yf.exam.core.utils.BeanMapper; +import com.yf.exam.core.utils.passwd.PassHandler; +import com.yf.exam.core.utils.passwd.PassInfo; +import com.yf.exam.modules.sys.user.dto.SysUserDTO; +import com.yf.exam.modules.sys.user.dto.request.SysUserSaveReqDTO; +import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; +import com.yf.exam.modules.sys.user.entity.SysUser; +import com.yf.exam.modules.sys.user.mapper.SysUserMapper; +import com.yf.exam.modules.sys.user.service.SysUserRoleService; +import com.yf.exam.modules.sys.user.service.SysUserService; +import com.yf.exam.modules.user.UserUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.SecurityUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; + +/** +*

+* 语言设置 服务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-04-13 16:57 +*/ +@Service +public class SysUserServiceImpl extends ServiceImpl implements SysUserService { + + @Autowired + private SysUserRoleService sysUserRoleService; + + + @Override + public IPage paging(PagingReqDTO reqDTO) { + + //创建分页对象 + IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); + + //查询条件 + QueryWrapper wrapper = new QueryWrapper<>(); + + SysUserDTO params = reqDTO.getParams(); + + if(params!=null){ + if(!StringUtils.isBlank(params.getUserName())){ + wrapper.lambda().like(SysUser::getUserName, params.getUserName()); + } + + if(!StringUtils.isBlank(params.getRealName())){ + wrapper.lambda().like(SysUser::getRealName, params.getRealName()); + } + } + + //获得数据 + IPage page = this.page(query, wrapper); + //转换结果 + IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); + return pageData; + } + + @Override + public SysUserLoginDTO login(String userName, String password) { + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(SysUser::getUserName, userName); + + SysUser user = this.getOne(wrapper, false); + if(user == null){ + throw new ServiceException(ApiError.ERROR_90010002); + } + + // 被禁用 + if(user.getState().equals(CommonState.ABNORMAL)){ + throw new ServiceException(ApiError.ERROR_90010005); + } + + boolean check = PassHandler.checkPass(password,user.getSalt(), user.getPassword()); + if(!check){ + throw new ServiceException(ApiError.ERROR_90010002); + } + + return this.setToken(user); + } + + @Override + public SysUserLoginDTO token(String token) { + + // 获得会话 + String username = JwtUtils.getUsername(token); + + // 校验结果 + boolean check = JwtUtils.verify(token, username); + + if(!check){ + throw new ServiceException(ApiError.ERROR_90010002); + } + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(SysUser::getUserName, username); + + SysUser user = this.getOne(wrapper, false); + if(user == null){ + throw new ServiceException(ApiError.ERROR_10010002); + } + + // 被禁用 + if(user.getState().equals(CommonState.ABNORMAL)){ + throw new ServiceException(ApiError.ERROR_90010005); + } + + return this.setToken(user); + } + + @Override + public void logout(String token) { + + // 仅退出当前会话 + SecurityUtils.getSubject().logout(); + } + + @Override + public void update(SysUserDTO reqDTO) { + + + String pass = reqDTO.getPassword(); + if(!StringUtils.isBlank(pass)){ + PassInfo passInfo = PassHandler.buildPassword(pass); + SysUser user = this.getById(UserUtils.getUserId()); + user.setPassword(passInfo.getPassword()); + user.setSalt(passInfo.getSalt()); + this.updateById(user); + } + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void save(SysUserSaveReqDTO reqDTO) { + + List roles = reqDTO.getRoles(); + + if(CollectionUtils.isEmpty(roles)){ + throw new ServiceException(ApiError.ERROR_90010003); + } + + // 保存基本信息 + SysUser user = new SysUser(); + BeanMapper.copy(reqDTO, user); + + // 添加模式 + if(StringUtils.isBlank(user.getId())){ + user.setId(IdWorker.getIdStr()); + } + + // 修改密码 + if(!StringUtils.isBlank(reqDTO.getPassword())){ + PassInfo pass = PassHandler.buildPassword(reqDTO.getPassword()); + user.setPassword(pass.getPassword()); + user.setSalt(pass.getSalt()); + } + + // 保存角色信息 + String roleIds = sysUserRoleService.saveRoles(user.getId(), roles); + user.setRoleIds(roleIds); + this.saveOrUpdate(user); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public SysUserLoginDTO reg(SysUserDTO reqDTO) { + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(SysUser::getUserName, reqDTO.getUserName()); + + int count = this.count(wrapper); + + if(count > 0){ + throw new ServiceException(1, "用户名已存在,换一个吧!"); + } + + + // 保存用户 + SysUser user = new SysUser(); + user.setId(IdWorker.getIdStr()); + user.setUserName(reqDTO.getUserName()); + user.setRealName(reqDTO.getRealName()); + PassInfo passInfo = PassHandler.buildPassword(reqDTO.getPassword()); + user.setPassword(passInfo.getPassword()); + user.setSalt(passInfo.getSalt()); + + // 保存角色 + List roles = new ArrayList<>(); + roles.add("student"); + String roleIds = sysUserRoleService.saveRoles(user.getId(), roles); + user.setRoleIds(roleIds); + this.save(user); + + return this.setToken(user); + } + + @Override + public SysUserLoginDTO quickReg(SysUserDTO reqDTO) { + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(SysUser::getUserName, reqDTO.getUserName()); + wrapper.last(" LIMIT 1 "); + SysUser user = this.getOne(wrapper); + if(user!=null){ + return this.setToken(user); + } + + return this.reg(reqDTO); + } + + + /** + * 保存会话信息 + * @param user + * @return + */ + private SysUserLoginDTO setToken(SysUser user){ + + SysUserLoginDTO respDTO = new SysUserLoginDTO(); + BeanMapper.copy(user, respDTO); + + // 生成Token + String token = JwtUtils.sign(user.getUserName()); + respDTO.setToken(token); + + // 填充角色 + List roles = sysUserRoleService.listRoles(user.getId()); + respDTO.setRoles(roles); + + return respDTO; + } +} diff --git a/src/main/java/com/guwan/backend/model/user/UserUtils.java b/src/main/java/com/guwan/backend/model/user/UserUtils.java new file mode 100644 index 0000000..13a5340 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/user/UserUtils.java @@ -0,0 +1,56 @@ +package com.guwan.backend.model.user; + +import com.yf.exam.core.api.ApiError; +import com.yf.exam.core.exception.ServiceException; +import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; +import org.apache.shiro.SecurityUtils; + +/** + * 用户静态工具类 + * @author bool + */ +public class UserUtils { + + + /** + * 获取当前登录用户的ID + * @param throwable + * @return + */ + public static String getUserId(boolean throwable){ + try { + return ((SysUserLoginDTO) SecurityUtils.getSubject().getPrincipal()).getId(); + }catch (Exception e){ + if(throwable){ + throw new ServiceException(ApiError.ERROR_10010002); + } + return null; + } + } + + /** + * 获取当前登录用户的ID + * @param throwable + * @return + */ + public static boolean isAdmin(boolean throwable){ + try { + SysUserLoginDTO dto = ((SysUserLoginDTO) SecurityUtils.getSubject().getPrincipal()); + return dto.getRoles().contains("sa"); + }catch (Exception e){ + if(throwable){ + throw new ServiceException(ApiError.ERROR_10010002); + } + } + + return false; + } + + /** + * 获取当前登录用户的ID,默认是会抛异常的 + * @return + */ + public static String getUserId(){ + return getUserId(true); + } +} diff --git a/src/main/java/com/guwan/backend/model/user/book/controller/UserBookController.java b/src/main/java/com/guwan/backend/model/user/book/controller/UserBookController.java new file mode 100644 index 0000000..6639709 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/user/book/controller/UserBookController.java @@ -0,0 +1,76 @@ +package com.guwan.backend.model.user.book.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.yf.exam.core.api.ApiRest; +import com.yf.exam.core.api.controller.BaseController; +import com.yf.exam.core.api.dto.BaseIdRespDTO; +import com.yf.exam.core.api.dto.BaseIdsReqDTO; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.user.book.dto.UserBookDTO; +import com.yf.exam.modules.user.book.service.UserBookService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** +*

+* 错题本控制器 +*

+* +* @author 聪明笨狗 +* @since 2020-05-27 17:56 +*/ +@Api(tags={"错题本"}) +@RestController +@RequestMapping("/exam/api/user/wrong-book") +public class UserBookController extends BaseController { + + @Autowired + private UserBookService baseService; + + + /** + * 批量删除 + * @param reqDTO + * @return + */ + @ApiOperation(value = "批量删除") + @RequestMapping(value = "/delete", method = { RequestMethod.POST}) + public ApiRest delete(@RequestBody BaseIdsReqDTO reqDTO) { + //根据ID删除 + baseService.removeByIds(reqDTO.getIds()); + return super.success(); + } + + /** + * 分页查找 + * @param reqDTO + * @return + */ + @ApiOperation(value = "分页查找") + @RequestMapping(value = "/paging", method = { RequestMethod.POST}) + public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { + + //分页查询并转换 + IPage page = baseService.paging(reqDTO); + + return super.success(page); + } + + /** + * 查找列表,每次最多返回200条数据 + * @param reqDTO + * @return + */ + @ApiOperation(value = "查找列表") + @RequestMapping(value = "/next", method = { RequestMethod.POST}) + public ApiRest nextQu(@RequestBody UserBookDTO reqDTO) { + //转换并返回 + String quId = baseService.findNext(reqDTO.getExamId(), reqDTO.getQuId()); + return super.success(new BaseIdRespDTO(quId)); + } +} diff --git a/src/main/java/com/guwan/backend/model/user/book/dto/UserBookDTO.java b/src/main/java/com/guwan/backend/model/user/book/dto/UserBookDTO.java new file mode 100644 index 0000000..3c75462 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/user/book/dto/UserBookDTO.java @@ -0,0 +1,52 @@ +package com.guwan.backend.model.user.book.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** +*

+* 错题本请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-27 17:56 +*/ +@Data +@ApiModel(value="错题本", description="错题本") +public class UserBookDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "ID", required=true) + private String id; + + @ApiModelProperty(value = "考试ID", required=true) + private String examId; + + @ApiModelProperty(value = "用户ID", required=true) + private String userId; + + @ApiModelProperty(value = "题目ID", required=true) + private String quId; + + @ApiModelProperty(value = "加入时间", required=true) + private Date createTime; + + @ApiModelProperty(value = "最近错误时间", required=true) + private Date updateTime; + + @ApiModelProperty(value = "错误时间", required=true) + private Integer wrongCount; + + @ApiModelProperty(value = "题目标题", required=true) + private String title; + + @ApiModelProperty(value = "错题序号", required=true) + private Integer sort; + +} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/model/user/book/entity/UserBook.java b/src/main/java/com/guwan/backend/model/user/book/entity/UserBook.java new file mode 100644 index 0000000..52ec856 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/user/book/entity/UserBook.java @@ -0,0 +1,78 @@ +package com.guwan.backend.model.user.book.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +import java.util.Date; + +/** +*

+* 错题本实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-27 17:56 +*/ +@Data +@TableName("el_user_book") +public class UserBook extends Model { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 考试ID + */ + @TableField("exam_id") + private String examId; + + /** + * 用户ID + */ + @TableField("user_id") + private String userId; + + /** + * 题目ID + */ + @TableField("qu_id") + private String quId; + + /** + * 加入时间 + */ + @TableField("create_time") + private Date createTime; + + /** + * 最近错误时间 + */ + @TableField("update_time") + private Date updateTime; + + /** + * 错误时间 + */ + @TableField("wrong_count") + private Integer wrongCount; + + /** + * 题目标题 + */ + private String title; + + /** + * 错题序号 + */ + private Integer sort; + +} diff --git a/src/main/java/com/guwan/backend/model/user/book/mapper/UserBookMapper.java b/src/main/java/com/guwan/backend/model/user/book/mapper/UserBookMapper.java new file mode 100644 index 0000000..06e3105 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/user/book/mapper/UserBookMapper.java @@ -0,0 +1,16 @@ +package com.guwan.backend.model.user.book.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yf.exam.modules.user.book.entity.UserBook; + +/** +*

+* 错题本Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-05-27 17:56 +*/ +public interface UserBookMapper extends BaseMapper { + +} diff --git a/src/main/java/com/guwan/backend/model/user/book/service/UserBookService.java b/src/main/java/com/guwan/backend/model/user/book/service/UserBookService.java new file mode 100644 index 0000000..8556aab --- /dev/null +++ b/src/main/java/com/guwan/backend/model/user/book/service/UserBookService.java @@ -0,0 +1,40 @@ +package com.guwan.backend.model.user.book.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.user.book.dto.UserBookDTO; +import com.yf.exam.modules.user.book.entity.UserBook; + +/** +*

+* 错题本业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-27 17:56 +*/ +public interface UserBookService extends IService { + + /** + * 分页查询数据 + * @param reqDTO + * @return + */ + IPage paging(PagingReqDTO reqDTO); + + /** + * 加入错题本 + * @param quId + * @param examId + */ + void addBook(String examId, String quId); + + /** + * 查找第一个错题 + * @param quId + * @param examId + * @return + */ + String findNext(String examId, String quId); +} diff --git a/src/main/java/com/guwan/backend/model/user/book/service/impl/UserBookServiceImpl.java b/src/main/java/com/guwan/backend/model/user/book/service/impl/UserBookServiceImpl.java new file mode 100644 index 0000000..1d2073d --- /dev/null +++ b/src/main/java/com/guwan/backend/model/user/book/service/impl/UserBookServiceImpl.java @@ -0,0 +1,155 @@ +package com.guwan.backend.model.user.book.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.qu.entity.Qu; +import com.yf.exam.modules.qu.service.QuService; +import com.yf.exam.modules.user.UserUtils; +import com.yf.exam.modules.user.book.dto.UserBookDTO; +import com.yf.exam.modules.user.book.entity.UserBook; +import com.yf.exam.modules.user.book.mapper.UserBookMapper; +import com.yf.exam.modules.user.book.service.UserBookService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +/** +*

+* 语言设置 服务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-27 17:56 +*/ +@Service +public class UserBookServiceImpl extends ServiceImpl implements UserBookService { + + @Autowired + private QuService quService; + + @Override + public IPage paging(PagingReqDTO reqDTO) { + + //创建分页对象 + Page query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); + + //查询条件 + QueryWrapper wrapper = new QueryWrapper<>(); + // 查找用户的错题 + wrapper.lambda().eq(UserBook::getUserId, UserUtils.getUserId(true)); + + UserBookDTO params = reqDTO.getParams(); + if(params!=null){ + if(!StringUtils.isEmpty(params.getTitle())){ + wrapper.lambda().like(UserBook::getTitle, params.getTitle()); + } + + if(!StringUtils.isEmpty(params.getExamId())){ + wrapper.lambda().eq(UserBook::getExamId, params.getExamId()); + } + } + + //获得数据 + IPage page = this.page(query, wrapper); + //转换结果 + IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); + return pageData; + } + + + + @Override + public void addBook(String examId, String quId) { + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda() + .eq(UserBook::getUserId, UserUtils.getUserId()) + .eq(UserBook::getExamId, examId) + .eq(UserBook::getQuId, quId); + + //查找已有的错题信息 + UserBook book = this.getOne(wrapper, false); + + + // 问题 + Qu qu = quService.getById(quId); + + if (book == null) { + book = new UserBook(); + book.setExamId(examId); + book.setUserId(UserUtils.getUserId()); + book.setTitle(qu.getContent()); + book.setQuId(quId); + book.setWrongCount(1); + Integer maxSort = this.findMaxSort(examId, UserUtils.getUserId()); + book.setSort(maxSort+1); + + this.save(book); + } else { + book.setWrongCount(book.getWrongCount()+1); + this.updateById(book); + } + } + + @Override + public String findNext(String examId, String quId) { + + + Integer sort = 999999; + + if(!StringUtils.isEmpty(quId)){ + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda() + .eq(UserBook::getUserId, UserUtils.getUserId()) + .eq(UserBook::getExamId, examId) + .eq(UserBook::getQuId, quId); + wrapper.last(" ORDER BY `sort` DESC"); + + UserBook last = this.getOne(wrapper, false); + if(last!=null){ + sort = last.getSort(); + } + } + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda() + .eq(UserBook::getUserId, UserUtils.getUserId()) + .eq(UserBook::getExamId, examId) + .lt(UserBook::getSort, sort); + wrapper.last(" ORDER BY `sort` DESC"); + + UserBook next = this.getOne(wrapper, false); + if(next != null){ + return next.getQuId(); + } + + return null; + } + + /** + * 查找最大的排序 + * @param userId + * @return + */ + private Integer findMaxSort(String examId, String userId){ + + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda() + .eq(UserBook::getExamId, examId) + .eq(UserBook::getUserId, userId); + wrapper.last(" ORDER BY `sort` DESC"); + + UserBook book = this.getOne(wrapper, false); + if(book == null){ + return 0; + } + return book.getSort(); + } + + +} diff --git a/src/main/java/com/guwan/backend/model/user/exam/controller/UserExamController.java b/src/main/java/com/guwan/backend/model/user/exam/controller/UserExamController.java new file mode 100644 index 0000000..6636440 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/user/exam/controller/UserExamController.java @@ -0,0 +1,65 @@ +package com.guwan.backend.model.user.exam.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.yf.exam.core.api.ApiRest; +import com.yf.exam.core.api.controller.BaseController; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.user.exam.dto.request.UserExamReqDTO; +import com.yf.exam.modules.user.exam.dto.response.UserExamRespDTO; +import com.yf.exam.modules.user.exam.service.UserExamService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** +*

+* 考试记录控制器 +*

+* +* @author 聪明笨狗 +* @since 2020-09-21 15:13 +*/ +@Api(tags={"考试记录"}) +@RestController +@RequestMapping("/exam/api/user/exam") +public class UserExamController extends BaseController { + + @Autowired + private UserExamService baseService; + + + /** + * 分页查找 + * @param reqDTO + * @return + */ + @ApiOperation(value = "分页查找") + @RequestMapping(value = "/paging", method = { RequestMethod.POST}) + public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { + + //分页查询并转换 + IPage page = baseService.paging(reqDTO); + + return super.success(page); + } + + + /** + * 分页查找 + * @param reqDTO + * @return + */ + @ApiOperation(value = "分页查找") + @RequestMapping(value = "/my-paging", method = { RequestMethod.POST}) + public ApiRest> myPaging(@RequestBody PagingReqDTO reqDTO) { + + //分页查询并转换 + IPage page = baseService.myPaging(reqDTO); + + return super.success(page); + } +} diff --git a/src/main/java/com/guwan/backend/model/user/exam/dto/UserExamDTO.java b/src/main/java/com/guwan/backend/model/user/exam/dto/UserExamDTO.java new file mode 100644 index 0000000..5f9cb56 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/user/exam/dto/UserExamDTO.java @@ -0,0 +1,50 @@ +package com.guwan.backend.model.user.exam.dto; + +import com.yf.exam.core.annon.Dict; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** +*

+* 考试记录数据传输类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-21 15:13 +*/ +@Data +@ApiModel(value="考试记录", description="考试记录") +public class UserExamDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + private String id; + + @ApiModelProperty(value = "用户ID", required=true) + private String userId; + + @Dict(dictTable = "el_exam", dicText = "title", dicCode = "id") + @ApiModelProperty(value = "考试ID", required=true) + private String examId; + + @ApiModelProperty(value = "考试次数", required=true) + private Integer tryCount; + + @ApiModelProperty(value = "最高分数", required=true) + private Integer maxScore; + + @ApiModelProperty(value = "是否通过", required=true) + private Boolean passed; + + @ApiModelProperty(value = "创建时间") + private Date createTime; + + @ApiModelProperty(value = "更新时间") + private Date updateTime; + +} diff --git a/src/main/java/com/guwan/backend/model/user/exam/dto/request/UserExamReqDTO.java b/src/main/java/com/guwan/backend/model/user/exam/dto/request/UserExamReqDTO.java new file mode 100644 index 0000000..0ad7a53 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/user/exam/dto/request/UserExamReqDTO.java @@ -0,0 +1,30 @@ +package com.guwan.backend.model.user.exam.dto.request; + +import com.yf.exam.modules.user.exam.dto.UserExamDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** +*

+* 考试记录数据传输类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-21 15:13 +*/ +@Data +@ApiModel(value="考试记录", description="考试记录") +public class UserExamReqDTO extends UserExamDTO { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "考试名称", required=true) + private String title; + + @ApiModelProperty(value = "人员名称", required=true) + private String realName; + + +} diff --git a/src/main/java/com/guwan/backend/model/user/exam/dto/response/UserExamRespDTO.java b/src/main/java/com/guwan/backend/model/user/exam/dto/response/UserExamRespDTO.java new file mode 100644 index 0000000..567fee5 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/user/exam/dto/response/UserExamRespDTO.java @@ -0,0 +1,29 @@ +package com.guwan.backend.model.user.exam.dto.response; + +import com.yf.exam.modules.user.exam.dto.UserExamDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** +*

+* 考试记录数据传输类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-21 15:13 +*/ +@Data +@ApiModel(value="考试记录", description="考试记录") +public class UserExamRespDTO extends UserExamDTO { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "考试名称", required=true) + private String title; + + @ApiModelProperty(value = "人员名称", required=true) + private String realName; + +} diff --git a/src/main/java/com/guwan/backend/model/user/exam/entity/UserExam.java b/src/main/java/com/guwan/backend/model/user/exam/entity/UserExam.java new file mode 100644 index 0000000..f4b6d1b --- /dev/null +++ b/src/main/java/com/guwan/backend/model/user/exam/entity/UserExam.java @@ -0,0 +1,70 @@ +package com.guwan.backend.model.user.exam.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; + +import java.util.Date; + +/** +*

+* 考试记录实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-21 15:13 +*/ +@Data +@TableName("el_user_exam") +public class UserExam extends Model { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 用户ID + */ + @TableField("user_id") + private String userId; + + /** + * 考试ID + */ + @TableField("exam_id") + private String examId; + + /** + * 考试次数 + */ + @TableField("try_count") + private Integer tryCount; + + /** + * 最高分数 + */ + @TableField("max_score") + private Integer maxScore; + + /** + * 是否通过 + */ + private Boolean passed; + + /** + * 创建时间 + */ + @TableField("create_time") + private Date createTime; + + /** + * 更新时间 + */ + @TableField("update_time") + private Date updateTime; + +} diff --git a/src/main/java/com/guwan/backend/model/user/exam/mapper/UserExamMapper.java b/src/main/java/com/guwan/backend/model/user/exam/mapper/UserExamMapper.java new file mode 100644 index 0000000..92372c6 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/user/exam/mapper/UserExamMapper.java @@ -0,0 +1,29 @@ +package com.guwan.backend.model.user.exam.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.yf.exam.modules.user.exam.dto.request.UserExamReqDTO; +import com.yf.exam.modules.user.exam.dto.response.UserExamRespDTO; +import com.yf.exam.modules.user.exam.entity.UserExam; +import org.apache.ibatis.annotations.Param; + +/** +*

+* 考试记录Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-09-21 15:13 +*/ +public interface UserExamMapper extends BaseMapper { + + /** + * 我的考试分页 + * @param page + * @param query + * @return + */ + IPage paging(Page page, @Param("query") UserExamReqDTO query); + +} diff --git a/src/main/java/com/guwan/backend/model/user/exam/service/UserExamService.java b/src/main/java/com/guwan/backend/model/user/exam/service/UserExamService.java new file mode 100644 index 0000000..cf859b8 --- /dev/null +++ b/src/main/java/com/guwan/backend/model/user/exam/service/UserExamService.java @@ -0,0 +1,43 @@ +package com.guwan.backend.model.user.exam.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.user.exam.dto.request.UserExamReqDTO; +import com.yf.exam.modules.user.exam.dto.response.UserExamRespDTO; +import com.yf.exam.modules.user.exam.entity.UserExam; + +/** +*

+* 考试记录业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-21 15:13 +*/ +public interface UserExamService extends IService { + + /** + * 分页查询数据 + * @param reqDTO + * @return + */ + IPage paging(PagingReqDTO reqDTO); + + /** + * 分页查询数据 + * @param reqDTO + * @return + */ + IPage myPaging(PagingReqDTO reqDTO); + + + /** + * 考试完成后加入成绩 + * @param userId + * @param examId + * @param score + * @param passed + */ + void joinResult(String userId, String examId, Integer score, boolean passed); +} diff --git a/src/main/java/com/guwan/backend/model/user/exam/service/impl/UserExamServiceImpl.java b/src/main/java/com/guwan/backend/model/user/exam/service/impl/UserExamServiceImpl.java new file mode 100644 index 0000000..22d39fc --- /dev/null +++ b/src/main/java/com/guwan/backend/model/user/exam/service/impl/UserExamServiceImpl.java @@ -0,0 +1,88 @@ +package com.guwan.backend.model.user.exam.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.user.UserUtils; +import com.yf.exam.modules.user.exam.dto.request.UserExamReqDTO; +import com.yf.exam.modules.user.exam.dto.response.UserExamRespDTO; +import com.yf.exam.modules.user.exam.entity.UserExam; +import com.yf.exam.modules.user.exam.mapper.UserExamMapper; +import com.yf.exam.modules.user.exam.service.UserExamService; +import org.springframework.stereotype.Service; + +import java.util.Date; + +/** +*

+* 考试记录业务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-21 15:13 +*/ +@Service +public class UserExamServiceImpl extends ServiceImpl implements UserExamService { + + @Override + public IPage paging(PagingReqDTO reqDTO) { + + //转换结果 + IPage pageData = baseMapper.paging(reqDTO.toPage(), reqDTO.getParams()); + return pageData; + } + + @Override + public IPage myPaging(PagingReqDTO reqDTO) { + + UserExamReqDTO params = reqDTO.getParams(); + + + if(params==null){ + params = new UserExamReqDTO(); + } + + params.setUserId(UserUtils.getUserId()); + + + //转换结果 + IPage pageData = baseMapper.paging(reqDTO.toPage(), params); + return pageData; + } + + @Override + public void joinResult(String userId, String examId, Integer score, boolean passed) { + + //查询条件 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(UserExam::getUserId, userId) + .eq(UserExam::getExamId, examId); + + UserExam record = this.getOne(wrapper, false); + if(record == null){ + record = new UserExam(); + record.setCreateTime(new Date()); + record.setUpdateTime(new Date()); + record.setUserId(userId); + record.setExamId(examId); + record.setMaxScore(score); + record.setPassed(passed); + this.save(record); + return; + } + + // 修复低分数不加入统计问题 + record.setTryCount(record.getTryCount()+1); + record.setUpdateTime(new Date()); + + if(record.getMaxScore() < score){ + record.setMaxScore(score); + record.setPassed(passed); + } + + this.updateById(record); + + + } +} diff --git a/src/main/java/com/guwan/backend/test/Father.java b/src/main/java/com/guwan/backend/test/Father.java new file mode 100644 index 0000000..de35f6a --- /dev/null +++ b/src/main/java/com/guwan/backend/test/Father.java @@ -0,0 +1,15 @@ +package com.guwan.backend.test; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Father { + private String name; + private List son; +} diff --git a/src/main/java/com/guwan/backend/test/FatherCopy.java b/src/main/java/com/guwan/backend/test/FatherCopy.java new file mode 100644 index 0000000..a210eee --- /dev/null +++ b/src/main/java/com/guwan/backend/test/FatherCopy.java @@ -0,0 +1,15 @@ +package com.guwan.backend.test; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class FatherCopy { + private String name; + private List son; +} diff --git a/src/main/java/com/guwan/backend/test/Son.java b/src/main/java/com/guwan/backend/test/Son.java new file mode 100644 index 0000000..0db81a9 --- /dev/null +++ b/src/main/java/com/guwan/backend/test/Son.java @@ -0,0 +1,12 @@ +package com.guwan.backend.test; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Son { + private String name; +} diff --git a/src/main/java/com/guwan/backend/test/TestCopy.java b/src/main/java/com/guwan/backend/test/TestCopy.java new file mode 100644 index 0000000..088c63d --- /dev/null +++ b/src/main/java/com/guwan/backend/test/TestCopy.java @@ -0,0 +1,22 @@ +package com.guwan.backend.test; + +import org.dozer.DozerBeanMapper; +import org.springframework.beans.BeanUtils; + +import java.util.List; + +public class TestCopy { + public static void main(String[] args) { + Son son = new Son("儿子"); + Father father = new Father("父亲", List.of(son)); + FatherCopy fatherCopy = new FatherCopy(); + System.out.println("father = " + father); + BeanUtils.copyProperties(father, fatherCopy); + System.out.println("fatherCopy = " + fatherCopy); + FatherCopy fatherCopy2 = new FatherCopy(); + DozerBeanMapper dozerBeanMapper = new DozerBeanMapper(); + dozerBeanMapper.map(father, fatherCopy2); + System.out.println("fatherCopy2 = " + fatherCopy2); + + } +} diff --git a/src/main/java/com/guwan/backend/util/MinioUtil.java b/src/main/java/com/guwan/backend/util/MinioUtil.java index bcd82f8..2ecf43e 100644 --- a/src/main/java/com/guwan/backend/util/MinioUtil.java +++ b/src/main/java/com/guwan/backend/util/MinioUtil.java @@ -1,7 +1,7 @@ package com.guwan.backend.util; import io.minio.*; -import io.minio.errors.MinioException; +import io.minio.errors.*; import io.minio.http.Method; import io.minio.messages.DeleteError; import io.minio.messages.DeleteObject; @@ -225,6 +225,23 @@ public class MinioUtil { + public InputStream getFileInputStream(String bucket, String object) { + try { + return minioClient.getObject( + GetObjectArgs.builder() + .bucket(bucket) + .object(object) + .build() + ); + + + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + // 初始化时创建视频桶 // @PostConstruct // public void init() { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 00fb062..777e6c6 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -212,7 +212,7 @@ logging: xxl: job: admin: - addresses: http://192.168.0.121:9001/xxl-job-admin + addresses: http://192.168.0.122:9001/xxl-job-admin accessToken: GuwanTest executor: appname: xxl-job-executor-guwan @@ -225,3 +225,13 @@ xxl: docker: host: tcp://localhost:2375 api-version: 1.45 + +langchain4j: + community: + dashscope: + chat-model: + api-key: sk-80629d0870da4662825d28d09bba5000 + model-name: qwen-max + streaming-chat-model: + api-key: sk-80629d0870da4662825d28d09bba5000 + model-name: qwen-max \ No newline at end of file diff --git a/src/main/resources/mapper/exam/ExamDepartMapper.xml b/src/main/resources/mapper/exam/ExamDepartMapper.xml new file mode 100644 index 0000000..ee6e180 --- /dev/null +++ b/src/main/resources/mapper/exam/ExamDepartMapper.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + `id`,`exam_id`,`depart_id` + + + diff --git a/src/main/resources/mapper/exam/ExamMapper.xml b/src/main/resources/mapper/exam/ExamMapper.xml new file mode 100644 index 0000000..81959f2 --- /dev/null +++ b/src/main/resources/mapper/exam/ExamMapper.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + `id`,`title`,`content`,`open_type`,`join_type`,`level`,`state`,`time_limit`,`start_time`,`end_time`,`create_time`,`update_time`,`total_score`,`total_time`,`qualify_score` + + + + + + + + + + + diff --git a/src/main/resources/mapper/exam/ExamRepoMapper.xml b/src/main/resources/mapper/exam/ExamRepoMapper.xml new file mode 100644 index 0000000..453733c --- /dev/null +++ b/src/main/resources/mapper/exam/ExamRepoMapper.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + `id`,`exam_id`,`repo_id`,`radio_count`,`radio_score`,`multi_count`,`multi_score`,`judge_count`,`judge_score` + + + + + + + + + + +