From c87fb476d60e191383ab0e74ffad99f0a0b86a66 Mon Sep 17 00:00:00 2001 From: Jerry <707344974@qq.com> Date: Thu, 29 Oct 2020 18:55:12 +0800 Subject: [PATCH] =?UTF-8?q?commit=EF=BC=9A=E6=94=AF=E6=8C=81app=E7=9A=84?= =?UTF-8?q?=E7=BA=AF=E5=90=8E=E5=8F=B0=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- orange-demo-single-service-for-app/.gitignore | 26 + orange-demo-single-service-for-app/README.md | 10 + .../application-common/pom.xml | 24 + .../common/constant/DeviceType.java | 49 + .../application/common/constant/ExpLevel.java | 49 + .../application/common/constant/Gender.java | 44 + .../common/constant/StudentActionType.java | 89 + .../common/constant/StudentStatus.java | 49 + .../application/common/constant/Subject.java | 49 + .../application/pom.xml | 72 + .../java/com/orange/demo/MyApplication.java | 18 + .../app/controller/AreaCodeController.java | 58 + .../demo/app/controller/CourseController.java | 290 ++ .../CourseTransStatsController.java | 100 + .../demo/app/controller/GradeController.java | 115 + .../app/controller/SchoolInfoController.java | 168 + .../StudentActionStatsController.java | 100 + .../StudentActionTransController.java | 159 + .../controller/StudentClassController.java | 426 ++ .../app/controller/StudentController.java | 180 + .../orange/demo/app/dao/AreaCodeMapper.java | 13 + .../demo/app/dao/ClassCourseMapper.java | 13 + .../demo/app/dao/ClassStudentMapper.java | 13 + .../com/orange/demo/app/dao/CourseMapper.java | 52 + .../demo/app/dao/CourseTransStatsMapper.java | 41 + .../com/orange/demo/app/dao/GradeMapper.java | 13 + .../demo/app/dao/MaterialEditionMapper.java | 13 + .../orange/demo/app/dao/SchoolInfoMapper.java | 26 + .../app/dao/StudentActionStatsMapper.java | 41 + .../app/dao/StudentActionTransMapper.java | 26 + .../demo/app/dao/StudentClassMapper.java | 26 + .../orange/demo/app/dao/StudentMapper.java | 52 + .../demo/app/dao/mapper/AreaCodeMapper.xml | 10 + .../demo/app/dao/mapper/ClassCourseMapper.xml | 9 + .../app/dao/mapper/ClassStudentMapper.xml | 8 + .../demo/app/dao/mapper/CourseMapper.xml | 101 + .../app/dao/mapper/CourseTransStatsMapper.xml | 60 + .../demo/app/dao/mapper/GradeMapper.xml | 9 + .../app/dao/mapper/MaterialEditionMapper.xml | 9 + .../demo/app/dao/mapper/SchoolInfoMapper.xml | 35 + .../dao/mapper/StudentActionStatsMapper.xml | 86 + .../dao/mapper/StudentActionTransMapper.xml | 57 + .../app/dao/mapper/StudentClassMapper.xml | 40 + .../demo/app/dao/mapper/StudentMapper.xml | 101 + .../com/orange/demo/app/model/AreaCode.java | 48 + .../orange/demo/app/model/ClassCourse.java | 46 + .../orange/demo/app/model/ClassStudent.java | 38 + .../com/orange/demo/app/model/Course.java | 197 + .../demo/app/model/CourseTransStats.java | 139 + .../java/com/orange/demo/app/model/Grade.java | 48 + .../demo/app/model/MaterialEdition.java | 45 + .../com/orange/demo/app/model/SchoolInfo.java | 76 + .../com/orange/demo/app/model/Student.java | 255 + .../demo/app/model/StudentActionStats.java | 236 + .../demo/app/model/StudentActionTrans.java | 192 + .../orange/demo/app/model/StudentClass.java | 128 + .../demo/app/model/constant/ClassLevel.java | 49 + .../demo/app/model/constant/ClassStatus.java | 44 + .../app/model/constant/CourseDifficult.java | 49 + .../demo/app/service/AreaCodeService.java | 57 + .../demo/app/service/CourseService.java | 175 + .../app/service/CourseTransStatsService.java | 83 + .../orange/demo/app/service/GradeService.java | 88 + .../demo/app/service/SchoolInfoService.java | 128 + .../service/StudentActionStatsService.java | 85 + .../service/StudentActionTransService.java | 130 + .../demo/app/service/StudentClassService.java | 255 + .../demo/app/service/StudentService.java | 202 + .../orange/demo/config/ApplicationConfig.java | 46 + .../orange/demo/config/DataSourceConfig.java | 30 + .../com/orange/demo/config/FilterConfig.java | 57 + .../orange/demo/config/InterceptorConfig.java | 21 + .../AuthenticationInterceptor.java | 103 + .../demo/upms/controller/LoginController.java | 142 + .../upms/controller/SysUserController.java | 177 + .../orange/demo/upms/dao/SysUserMapper.java | 26 + .../demo/upms/dao/mapper/SysUserMapper.xml | 51 + .../com/orange/demo/upms/model/SysUser.java | 152 + .../upms/model/constant/SysUserStatus.java | 44 + .../demo/upms/model/constant/SysUserType.java | 49 + .../demo/upms/service/SysUserService.java | 175 + .../src/main/resources/application.yml | 202 + .../application/src/main/resources/log4j2.xml | 73 + .../resources/template/views/print_error.ftl | 329 ++ .../common/common-core/pom.xml | 109 + .../core/advice/MyControllerAdvice.java | 30 + .../core/advice/MyExceptionHandler.java | 131 + .../core/annotation/DeletedFlagColumn.java | 16 + .../core/annotation/JobUpdateTimeColumn.java | 16 + .../common/core/annotation/MyDataSource.java | 21 + .../common/core/annotation/MyRequestBody.java | 31 + .../core/annotation/NoAuthInterface.java | 15 + .../core/annotation/RelationConstDict.java | 29 + .../common/core/annotation/RelationDict.java | 60 + .../core/annotation/RelationManyToMany.java | 38 + .../RelationManyToManyAggregation.java | 85 + .../RelationOneToManyAggregation.java | 57 + .../core/annotation/RelationOneToOne.java | 50 + .../core/annotation/UploadFlagColumn.java | 24 + .../demo/common/core/aop/AccessLogAspect.java | 82 + .../common/core/base/dao/BaseDaoMapper.java | 90 + .../core/base/mapper/BaseModelMapper.java | 124 + .../core/base/mapper/DummyModelMapper.java | 58 + .../core/base/service/BaseDictService.java | 149 + .../common/core/base/service/BaseService.java | 1380 ++++++ .../demo/common/core/cache/CacheConfig.java | 90 + .../common/core/cache/DictionaryCache.java | 88 + .../common/core/cache/MapDictionaryCache.java | 176 + .../core/cache/MapTreeDictionaryCache.java | 142 + .../common/core/cache/SessionCacheHelper.java | 97 + .../core/config/CommonWebMvcConfig.java | 67 + .../common/core/config/EncryptConfig.java | 20 + .../core/config/RestTemplateConfig.java | 64 + .../demo/common/core/config/TomcatConfig.java | 39 + .../common/core/constant/AggregationType.java | 81 + .../core/constant/ApplicationConstant.java | 55 + .../common/core/constant/ErrorCodeEnum.java | 81 + .../core/constant/GlobalDeletedFlag.java | 25 + .../exception/DataValidationException.java | 26 + .../exception/InvalidClassFieldException.java | 30 + .../exception/InvalidDataFieldException.java | 30 + .../exception/InvalidDataModelException.java | 27 + .../core/exception/MyRuntimeException.java | 36 + .../core/exception/NoDataAffectException.java | 26 + .../core/exception/NoDataPermException.java | 26 + .../exception/RedisCacheAccessException.java | 20 + .../MyRequestArgumentResolver.java | 226 + .../core/listener/LoadCachedDataListener.java | 28 + .../listener/LoadServiceRelationListener.java | 28 + .../demo/common/core/object/CallResult.java | 87 + .../common/core/object/MyGroupCriteria.java | 24 + .../demo/common/core/object/MyGroupParam.java | 167 + .../demo/common/core/object/MyOrderParam.java | 261 + .../demo/common/core/object/MyPageData.java | 23 + .../demo/common/core/object/MyPageParam.java | 58 + .../common/core/object/MyRelationParam.java | 84 + .../common/core/object/MyWhereCriteria.java | 308 ++ .../common/core/object/ResponseResult.java | 204 + .../demo/common/core/object/TokenData.java | 59 + .../demo/common/core/object/Tuple2.java | 50 + .../common/core/upload/BaseUpDownloader.java | 137 + .../common/core/upload/LocalUpDownloader.java | 149 + .../core/upload/UpDownloaderFactory.java | 49 + .../core/upload/UploadResponseInfo.java | 29 + .../common/core/upload/UploadStoreInfo.java | 22 + .../core/upload/UploadStoreTypeEnum.java | 19 + .../demo/common/core/util/AopTargetUtil.java | 64 + .../core/util/ApplicationContextHolder.java | 74 + .../demo/common/core/util/ContextUtil.java | 49 + .../demo/common/core/util/ExportUtil.java | 95 + .../demo/common/core/util/ImportUtil.java | 214 + .../orange/demo/common/core/util/IpUtil.java | 101 + .../orange/demo/common/core/util/JwtUtil.java | 110 + .../demo/common/core/util/LogMessageUtil.java | 33 + .../demo/common/core/util/MyCommonUtil.java | 163 + .../demo/common/core/util/MyDateUtil.java | 181 + .../demo/common/core/util/MyModelUtil.java | 463 ++ .../demo/common/core/util/MyPageUtil.java | 73 + .../orange/demo/common/core/util/RsaUtil.java | 115 + .../demo/common/core/util/TreeNode.java | 93 + .../demo/common/core/validator/AddGroup.java | 10 + .../common/core/validator/ConstDictRef.java | 48 + .../core/validator/ConstDictValidator.java | 33 + .../common/core/validator/TextLength.java | 55 + .../core/validator/TextLengthValidator.java | 39 + .../common/core/validator/UpdateGroup.java | 11 + .../common/common-sequence/pom.xml | 24 + .../config/IdGeneratorAutoConfigure.java | 14 + .../config/IdGeneratorProperties.java | 20 + .../sequence/generator/BasicIdGenerator.java | 48 + .../sequence/generator/MyIdGenerator.java | 24 + .../sequence/wrapper/IdGeneratorWrapper.java | 52 + .../main/resources/META-INF/spring.factories | 2 + .../common/common-swagger/pom.xml | 29 + .../config/SwaggerAutoConfiguration.java | 56 + .../swagger/config/SwaggerProperties.java | 44 + .../common/swagger/plugin/ByteBodyUtils.java | 85 + .../plugin/DynamicBodyModelPlugin.java | 61 + .../plugin/DynamicBodyParameterBuilder.java | 64 + .../main/resources/META-INF/spring.factories | 2 + .../common/pom.xml | 19 + orange-demo-single-service-for-app/pom.xml | 151 + .../zz-resource/api-docs/Api-Doc.md | 1295 +++++ .../zz-resource/api-docs/Postman-Api.json | 2493 ++++++++++ .../zz-resource/db-scripts/zz-orange-demo.sql | 4314 +++++++++++++++++ 185 files changed, 24073 insertions(+) create mode 100644 orange-demo-single-service-for-app/.gitignore create mode 100644 orange-demo-single-service-for-app/README.md create mode 100644 orange-demo-single-service-for-app/application-common/pom.xml create mode 100644 orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/DeviceType.java create mode 100644 orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/ExpLevel.java create mode 100644 orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/Gender.java create mode 100644 orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/StudentActionType.java create mode 100644 orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/StudentStatus.java create mode 100644 orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/Subject.java create mode 100644 orange-demo-single-service-for-app/application/pom.xml create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/MyApplication.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/AreaCodeController.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/CourseController.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/CourseTransStatsController.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/GradeController.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/SchoolInfoController.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/StudentActionStatsController.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/StudentActionTransController.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/StudentClassController.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/StudentController.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/AreaCodeMapper.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/ClassCourseMapper.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/ClassStudentMapper.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/CourseMapper.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/CourseTransStatsMapper.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/GradeMapper.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/MaterialEditionMapper.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/SchoolInfoMapper.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/StudentActionStatsMapper.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/StudentActionTransMapper.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/StudentClassMapper.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/StudentMapper.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/AreaCodeMapper.xml create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/ClassCourseMapper.xml create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/ClassStudentMapper.xml create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/CourseMapper.xml create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/CourseTransStatsMapper.xml create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/GradeMapper.xml create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/MaterialEditionMapper.xml create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/SchoolInfoMapper.xml create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/StudentActionStatsMapper.xml create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/StudentActionTransMapper.xml create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/StudentClassMapper.xml create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/StudentMapper.xml create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/AreaCode.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/ClassCourse.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/ClassStudent.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/Course.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/CourseTransStats.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/Grade.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/MaterialEdition.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/SchoolInfo.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/Student.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/StudentActionStats.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/StudentActionTrans.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/StudentClass.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/constant/ClassLevel.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/constant/ClassStatus.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/constant/CourseDifficult.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/AreaCodeService.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/CourseService.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/CourseTransStatsService.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/GradeService.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/SchoolInfoService.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/StudentActionStatsService.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/StudentActionTransService.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/StudentClassService.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/StudentService.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/config/ApplicationConfig.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/config/DataSourceConfig.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/config/FilterConfig.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/config/InterceptorConfig.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/interceptor/AuthenticationInterceptor.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/controller/LoginController.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/controller/SysUserController.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/dao/SysUserMapper.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/dao/mapper/SysUserMapper.xml create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/model/SysUser.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/model/constant/SysUserStatus.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/model/constant/SysUserType.java create mode 100644 orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/service/SysUserService.java create mode 100644 orange-demo-single-service-for-app/application/src/main/resources/application.yml create mode 100644 orange-demo-single-service-for-app/application/src/main/resources/log4j2.xml create mode 100644 orange-demo-single-service-for-app/application/src/main/resources/template/views/print_error.ftl create mode 100644 orange-demo-single-service-for-app/common/common-core/pom.xml create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/advice/MyControllerAdvice.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/advice/MyExceptionHandler.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/DeletedFlagColumn.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/JobUpdateTimeColumn.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/MyDataSource.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/MyRequestBody.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/NoAuthInterface.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationConstDict.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationDict.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationManyToMany.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationManyToManyAggregation.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationOneToManyAggregation.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationOneToOne.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/UploadFlagColumn.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/aop/AccessLogAspect.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/base/dao/BaseDaoMapper.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/base/mapper/BaseModelMapper.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/base/mapper/DummyModelMapper.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/base/service/BaseDictService.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/base/service/BaseService.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/cache/CacheConfig.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/cache/DictionaryCache.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/cache/MapDictionaryCache.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/cache/MapTreeDictionaryCache.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/cache/SessionCacheHelper.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/config/CommonWebMvcConfig.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/config/EncryptConfig.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/config/RestTemplateConfig.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/config/TomcatConfig.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/constant/AggregationType.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/constant/ApplicationConstant.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/constant/ErrorCodeEnum.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/constant/GlobalDeletedFlag.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/exception/DataValidationException.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/exception/InvalidClassFieldException.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/exception/InvalidDataFieldException.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/exception/InvalidDataModelException.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/exception/MyRuntimeException.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/exception/NoDataAffectException.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/exception/NoDataPermException.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/exception/RedisCacheAccessException.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/interceptor/MyRequestArgumentResolver.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/listener/LoadCachedDataListener.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/listener/LoadServiceRelationListener.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/object/CallResult.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/object/MyGroupCriteria.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/object/MyGroupParam.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/object/MyOrderParam.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/object/MyPageData.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/object/MyPageParam.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/object/MyRelationParam.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/object/MyWhereCriteria.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/object/ResponseResult.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/object/TokenData.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/object/Tuple2.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/upload/BaseUpDownloader.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/upload/LocalUpDownloader.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/upload/UpDownloaderFactory.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/upload/UploadResponseInfo.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/upload/UploadStoreInfo.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/upload/UploadStoreTypeEnum.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/util/AopTargetUtil.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/util/ApplicationContextHolder.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/util/ContextUtil.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/util/ExportUtil.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/util/ImportUtil.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/util/IpUtil.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/util/JwtUtil.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/util/LogMessageUtil.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/util/MyCommonUtil.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/util/MyDateUtil.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/util/MyModelUtil.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/util/MyPageUtil.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/util/RsaUtil.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/util/TreeNode.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/validator/AddGroup.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/validator/ConstDictRef.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/validator/ConstDictValidator.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/validator/TextLength.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/validator/TextLengthValidator.java create mode 100644 orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/validator/UpdateGroup.java create mode 100644 orange-demo-single-service-for-app/common/common-sequence/pom.xml create mode 100644 orange-demo-single-service-for-app/common/common-sequence/src/main/java/com/orange/demo/common/sequence/config/IdGeneratorAutoConfigure.java create mode 100644 orange-demo-single-service-for-app/common/common-sequence/src/main/java/com/orange/demo/common/sequence/config/IdGeneratorProperties.java create mode 100644 orange-demo-single-service-for-app/common/common-sequence/src/main/java/com/orange/demo/common/sequence/generator/BasicIdGenerator.java create mode 100644 orange-demo-single-service-for-app/common/common-sequence/src/main/java/com/orange/demo/common/sequence/generator/MyIdGenerator.java create mode 100644 orange-demo-single-service-for-app/common/common-sequence/src/main/java/com/orange/demo/common/sequence/wrapper/IdGeneratorWrapper.java create mode 100644 orange-demo-single-service-for-app/common/common-sequence/src/main/resources/META-INF/spring.factories create mode 100644 orange-demo-single-service-for-app/common/common-swagger/pom.xml create mode 100644 orange-demo-single-service-for-app/common/common-swagger/src/main/java/com/orange/demo/common/swagger/config/SwaggerAutoConfiguration.java create mode 100644 orange-demo-single-service-for-app/common/common-swagger/src/main/java/com/orange/demo/common/swagger/config/SwaggerProperties.java create mode 100644 orange-demo-single-service-for-app/common/common-swagger/src/main/java/com/orange/demo/common/swagger/plugin/ByteBodyUtils.java create mode 100644 orange-demo-single-service-for-app/common/common-swagger/src/main/java/com/orange/demo/common/swagger/plugin/DynamicBodyModelPlugin.java create mode 100644 orange-demo-single-service-for-app/common/common-swagger/src/main/java/com/orange/demo/common/swagger/plugin/DynamicBodyParameterBuilder.java create mode 100644 orange-demo-single-service-for-app/common/common-swagger/src/main/resources/META-INF/spring.factories create mode 100644 orange-demo-single-service-for-app/common/pom.xml create mode 100644 orange-demo-single-service-for-app/pom.xml create mode 100644 orange-demo-single-service-for-app/zz-resource/api-docs/Api-Doc.md create mode 100644 orange-demo-single-service-for-app/zz-resource/api-docs/Postman-Api.json create mode 100644 orange-demo-single-service-for-app/zz-resource/db-scripts/zz-orange-demo.sql diff --git a/orange-demo-single-service-for-app/.gitignore b/orange-demo-single-service-for-app/.gitignore new file mode 100644 index 00000000..ac242580 --- /dev/null +++ b/orange-demo-single-service-for-app/.gitignore @@ -0,0 +1,26 @@ +/target/ +!.mvn/wrapper/maven-wrapper.jar +/.mvn/* + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ \ No newline at end of file diff --git a/orange-demo-single-service-for-app/README.md b/orange-demo-single-service-for-app/README.md new file mode 100644 index 00000000..d73e7ded --- /dev/null +++ b/orange-demo-single-service-for-app/README.md @@ -0,0 +1,10 @@ +### 服务接口文档 +--- +- Knife4j + - 服务启动后,Knife4j的文档入口地址 [http://localhost:8082/doc.html#/plus](http://localhost:8082/doc.html#/plus) +- Postman + - 无需启动服务,即可将当前工程的接口导出成Postman格式。在工程的common/common-tools/模块下,找到ExportApiApp文件,并执行main函数。 + +### 服务启动环境依赖 +--- + diff --git a/orange-demo-single-service-for-app/application-common/pom.xml b/orange-demo-single-service-for-app/application-common/pom.xml new file mode 100644 index 00000000..0af5d4c2 --- /dev/null +++ b/orange-demo-single-service-for-app/application-common/pom.xml @@ -0,0 +1,24 @@ + + + + com.orange.demo + OrangeSingleDemo + 1.0.0 + + 4.0.0 + + application-common + 1.0.0 + application-common + jar + + + + com.orange.demo + common-core + 1.0.0 + + + \ No newline at end of file diff --git a/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/DeviceType.java b/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/DeviceType.java new file mode 100644 index 00000000..1dab32df --- /dev/null +++ b/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/DeviceType.java @@ -0,0 +1,49 @@ +package com.orange.demo.application.common.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 设备类型常量字典对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +public final class DeviceType { + + /** + * iOS。 + */ + public static final int IOS = 0; + /** + * Android。 + */ + public static final int ANDROID = 1; + /** + * PC。 + */ + public static final int PC = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(IOS, "iOS"); + DICT_MAP.put(ANDROID, "Android"); + DICT_MAP.put(PC, "PC"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private DeviceType() { + } +} diff --git a/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/ExpLevel.java b/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/ExpLevel.java new file mode 100644 index 00000000..acd2481f --- /dev/null +++ b/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/ExpLevel.java @@ -0,0 +1,49 @@ +package com.orange.demo.application.common.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 经验等级常量字典对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +public final class ExpLevel { + + /** + * 初级学员。 + */ + public static final int LOWER = 0; + /** + * 中级学员。 + */ + public static final int MIDDLE = 1; + /** + * 高级学员。 + */ + public static final int HIGH = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(LOWER, "初级学员"); + DICT_MAP.put(MIDDLE, "中级学员"); + DICT_MAP.put(HIGH, "高级学员"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private ExpLevel() { + } +} diff --git a/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/Gender.java b/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/Gender.java new file mode 100644 index 00000000..fe098160 --- /dev/null +++ b/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/Gender.java @@ -0,0 +1,44 @@ +package com.orange.demo.application.common.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 性别常量字典对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +public final class Gender { + + /** + * 男。 + */ + public static final int MALE = 1; + /** + * 女。 + */ + public static final int FEMALE = 0; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(MALE, "男"); + DICT_MAP.put(FEMALE, "女"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private Gender() { + } +} diff --git a/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/StudentActionType.java b/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/StudentActionType.java new file mode 100644 index 00000000..e546ff4e --- /dev/null +++ b/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/StudentActionType.java @@ -0,0 +1,89 @@ +package com.orange.demo.application.common.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 学生行为常量字典对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +public final class StudentActionType { + + /** + * 充值。 + */ + public static final int RECHARGE = 0; + /** + * 购课。 + */ + public static final int BUY_COURSE = 1; + /** + * 上课签到。 + */ + public static final int SIGNIN_COURSE = 2; + /** + * 上课签退。 + */ + public static final int SIGNOUT_COURSE = 3; + /** + * 看视频课。 + */ + public static final int WATCH_VIDEO = 4; + /** + * 做作业。 + */ + public static final int DO_PAPER = 5; + /** + * 刷题。 + */ + public static final int REFRESH_EXERCISE = 6; + /** + * 献花。 + */ + public static final int PRESENT_FLOWER = 7; + /** + * 购买视频。 + */ + public static final int BUY_VIDEO_COURSE = 8; + /** + * 购买鲜花。 + */ + public static final int BUY_FLOWER = 9; + /** + * 购买作业。 + */ + public static final int BUY_PAPER = 10; + + private static final Map DICT_MAP = new HashMap<>(11); + static { + DICT_MAP.put(RECHARGE, "充值"); + DICT_MAP.put(BUY_COURSE, "购课"); + DICT_MAP.put(SIGNIN_COURSE, "上课签到"); + DICT_MAP.put(SIGNOUT_COURSE, "上课签退"); + DICT_MAP.put(WATCH_VIDEO, "看视频课"); + DICT_MAP.put(DO_PAPER, "做作业"); + DICT_MAP.put(REFRESH_EXERCISE, "刷题"); + DICT_MAP.put(PRESENT_FLOWER, "献花"); + DICT_MAP.put(BUY_VIDEO_COURSE, "购买视频"); + DICT_MAP.put(BUY_FLOWER, "购买鲜花"); + DICT_MAP.put(BUY_PAPER, "购买作业"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private StudentActionType() { + } +} diff --git a/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/StudentStatus.java b/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/StudentStatus.java new file mode 100644 index 00000000..9c39f2b1 --- /dev/null +++ b/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/StudentStatus.java @@ -0,0 +1,49 @@ +package com.orange.demo.application.common.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 学生状态常量字典对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +public final class StudentStatus { + + /** + * 正常。 + */ + public static final int NORMAL = 0; + /** + * 锁定。 + */ + public static final int LOCKED = 1; + /** + * 注销。 + */ + public static final int DELETED = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(NORMAL, "正常"); + DICT_MAP.put(LOCKED, "锁定"); + DICT_MAP.put(DELETED, "注销"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private StudentStatus() { + } +} diff --git a/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/Subject.java b/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/Subject.java new file mode 100644 index 00000000..9bf21fb4 --- /dev/null +++ b/orange-demo-single-service-for-app/application-common/src/main/java/com/orange/demo/application/common/constant/Subject.java @@ -0,0 +1,49 @@ +package com.orange.demo.application.common.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 学科常量字典对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +public final class Subject { + + /** + * 语文。 + */ + public static final int CHINESE = 0; + /** + * 数学。 + */ + public static final int MATCH = 1; + /** + * 英语。 + */ + public static final int ENGLISH = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(CHINESE, "语文"); + DICT_MAP.put(MATCH, "数学"); + DICT_MAP.put(ENGLISH, "英语"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private Subject() { + } +} diff --git a/orange-demo-single-service-for-app/application/pom.xml b/orange-demo-single-service-for-app/application/pom.xml new file mode 100644 index 00000000..d363bf8c --- /dev/null +++ b/orange-demo-single-service-for-app/application/pom.xml @@ -0,0 +1,72 @@ + + + + com.orange.demo + OrangeSingleDemo + 1.0.0 + + 4.0.0 + + application + 1.0.0 + application + jar + + + + + com.orange.demo + common-core + 1.0.0 + + + com.orange.demo + common-sequence + 1.0.0 + + + com.orange.demo + application-common + 1.0.0 + + + com.orange.demo + common-swagger + 1.0.0 + + + + + + + src/main/resources + + **/*.* + + false + + + src/main/java + + **/*.xml + + false + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + + diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/MyApplication.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/MyApplication.java new file mode 100644 index 00000000..4914a72b --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/MyApplication.java @@ -0,0 +1,18 @@ +package com.orange.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * 应用服务启动类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@SpringBootApplication +public class MyApplication { + + public static void main(String[] args) { + SpringApplication.run(MyApplication.class, args); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/AreaCodeController.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/AreaCodeController.java new file mode 100644 index 00000000..ad6990c2 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/AreaCodeController.java @@ -0,0 +1,58 @@ +package com.orange.demo.app.controller; + +import io.swagger.annotations.Api; +import cn.jimmyshi.beanquery.BeanQuery; +import com.orange.demo.app.model.AreaCode; +import com.orange.demo.app.service.AreaCodeService; +import com.orange.demo.common.core.object.ResponseResult; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.*; + +/** + * 行政区划数据访问接口类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Api(tags = "行政区划数据访问接口") +@RestController +@RequestMapping("/admin/app/areaCode") +public class AreaCodeController { + + @Autowired + private AreaCodeService areaCodeService; + + /** + * 按照字典的形式返回行政区划列表。 + * + * @return 字典形式的行政区划列表。 + */ + @GetMapping("/listDictAreaCode") + public ResponseResult>> listDictAreaCode() { + List resultList = areaCodeService.getAllList(); + return ResponseResult.success(BeanQuery.select( + "parentId as parentId", "areaId as id", "areaName as name").executeFrom(resultList)); + } + + /** + * 根据上级行政区划Id获取其下级行政区划列表。 + * + * @param parentId 上级行政区划Id。 + * @return 按照字典的形式返回下级行政区划列表。 + */ + @GetMapping("/listDictAreaCodeByParentId") + public ResponseResult>> listDictAreaCodeByParentId(@RequestParam(required = false) Long parentId) { + Collection resultList = areaCodeService.getListByParentId(parentId); + if (CollectionUtils.isEmpty(resultList)) { + return ResponseResult.success(new LinkedList<>()); + } + return ResponseResult.success(BeanQuery.select( + "parentId as parentId", "areaId as id", "areaName as name").executeFrom(resultList)); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/CourseController.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/CourseController.java new file mode 100644 index 00000000..35cb268b --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/CourseController.java @@ -0,0 +1,290 @@ +package com.orange.demo.app.controller; + +import cn.jimmyshi.beanquery.BeanQuery; +import cn.hutool.core.util.ReflectUtil; +import com.orange.demo.common.core.upload.BaseUpDownloader; +import com.orange.demo.common.core.upload.UpDownloaderFactory; +import com.orange.demo.common.core.upload.UploadResponseInfo; +import com.orange.demo.common.core.upload.UploadStoreInfo; +import com.github.pagehelper.page.PageMethod; +import com.orange.demo.app.model.*; +import com.orange.demo.app.service.*; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.constant.*; +import com.orange.demo.common.core.annotation.MyRequestBody; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.cache.SessionCacheHelper; +import com.orange.demo.config.ApplicationConfig; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import io.swagger.annotations.Api; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.*; +import javax.validation.groups.Default; + +/** + * 课程数据操作控制器类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Api(tags = "课程数据管理接口") +@Slf4j +@RestController +@RequestMapping("/admin/app/course") +public class CourseController { + + @Autowired + private CourseService courseService; + @Autowired + private ApplicationConfig appConfig; + @Autowired + private SessionCacheHelper cacheHelper; + @Autowired + private UpDownloaderFactory upDownloaderFactory; + + /** + * 新增课程数据数据。 + * + * @param course 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @ApiOperationSupport(ignoreParameters = { + "course.courseId", + "course.priceStart", + "course.priceEnd", + "course.classHourStart", + "course.classHourEnd", + "course.createTimeStart", + "course.createTimeEnd"}) + @PostMapping("/add") + public ResponseResult add(@MyRequestBody Course course) { + String errorMessage = MyCommonUtil.getModelValidationError(course); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = courseService.verifyRelatedData(course, null); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + course = courseService.saveNew(course); + return ResponseResult.success(course.getCourseId()); + } + + /** + * 更新课程数据数据。 + * + * @param course 更新对象。 + * @return 应答结果对象。 + */ + @ApiOperationSupport(ignoreParameters = { + "course.priceStart", + "course.priceEnd", + "course.classHourStart", + "course.classHourEnd", + "course.createTimeStart", + "course.createTimeEnd"}) + @PostMapping("/update") + public ResponseResult update(@MyRequestBody Course course) { + String errorMessage = MyCommonUtil.getModelValidationError(course, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + Course originalCourse = courseService.getById(course.getCourseId()); + if (originalCourse == null) { + //NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = courseService.verifyRelatedData(course, originalCourse); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + if (!courseService.update(course, originalCourse)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除课程数据数据。 + * + * @param courseId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long courseId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(courseId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + Course originalCourse = courseService.getById(courseId); + if (originalCourse == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!courseService.remove(courseId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的课程数据列表。 + * + * @param courseFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody Course courseFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, Course.class); + List resultList = courseService.getCourseListWithRelation(courseFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定课程数据对象详情。 + * + * @param courseId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long courseId) { + if (MyCommonUtil.existBlankArgument(courseId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + Course course = courseService.getByIdWithRelation(courseId, MyRelationParam.full()); + if (course == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(course); + } + + /** + * 附件文件下载。 + * 这里将图片和其他类型的附件文件放到不同的父目录下,主要为了便于今后图片文件的迁移。 + * + * @param courseId 附件所在记录的主键Id。 + * @param fieldName 附件所属的字段名。 + * @param filename 文件名。如果没有提供该参数,就从当前记录的指定字段中读取。 + * @param asImage 下载文件是否为图片。 + * @param response Http 应答对象。 + */ + @GetMapping("/download") + public void download( + @RequestParam(required = false) Long courseId, + @RequestParam String fieldName, + @RequestParam String filename, + @RequestParam Boolean asImage, + HttpServletResponse response) { + if (MyCommonUtil.existBlankArgument(fieldName, filename, asImage)) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + // 使用try来捕获异常,是为了保证一旦出现异常可以返回500的错误状态,便于调试。 + // 否则有可能给前端返回的是200的错误码。 + try { + // 如果请求参数中没有包含主键Id,就判断该文件是否为当前session上传的。 + if (courseId == null) { + if (!cacheHelper.existSessionUploadFile(filename)) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN); + return; + } + } else { + Course course = courseService.getById(courseId); + if (course == null) { + ResponseResult.output(HttpServletResponse.SC_NOT_FOUND); + return; + } + String fieldJsonData = (String) ReflectUtil.getFieldValue(course, fieldName); + if (fieldJsonData == null) { + ResponseResult.output(HttpServletResponse.SC_BAD_REQUEST); + return; + } + if (!BaseUpDownloader.containFile(fieldJsonData, filename)) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN); + return; + } + } + UploadStoreInfo storeInfo = MyModelUtil.getUploadStoreInfo(Course.class, fieldName); + if (!storeInfo.isSupportUpload()) { + ResponseResult.output(HttpServletResponse.SC_NOT_IMPLEMENTED, + ResponseResult.error(ErrorCodeEnum.INVALID_UPLOAD_FIELD)); + return; + } + BaseUpDownloader upDownloader = upDownloaderFactory.get(storeInfo.getStoreType()); + upDownloader.doDownload(appConfig.getUploadFileBaseDir(), + Course.class.getSimpleName(), fieldName, filename, asImage, response); + } catch (Exception e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + log.error(e.getMessage(), e); + } + } + + /** + * 文件上传操作。 + * + * @param fieldName 上传文件名。 + * @param asImage 是否作为图片上传。如果是图片,今后下载的时候无需权限验证。否则就是附件上传,下载时需要权限验证。 + * @param uploadFile 上传文件对象。 + */ + @PostMapping("/upload") + public void upload( + @RequestParam String fieldName, + @RequestParam Boolean asImage, + @RequestParam("uploadFile") MultipartFile uploadFile) throws Exception { + UploadStoreInfo storeInfo = MyModelUtil.getUploadStoreInfo(Course.class, fieldName); + // 这里就会判断参数中指定的字段,是否支持上传操作。 + if (!storeInfo.isSupportUpload()) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, + ResponseResult.error(ErrorCodeEnum.INVALID_UPLOAD_FIELD)); + return; + } + // 根据字段注解中的存储类型,通过工厂方法获取匹配的上传下载实现类,从而解耦。 + BaseUpDownloader upDownloader = upDownloaderFactory.get(storeInfo.getStoreType()); + UploadResponseInfo responseInfo = upDownloader.doUpload(null, + appConfig.getUploadFileBaseDir(), Course.class.getSimpleName(), fieldName, asImage, uploadFile); + if (responseInfo.getUploadFailed()) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, + ResponseResult.error(ErrorCodeEnum.UPLOAD_FAILED, responseInfo.getErrorMessage())); + return; + } + cacheHelper.putSessionUploadFile(responseInfo.getFilename()); + ResponseResult.output(ResponseResult.success(responseInfo)); + } + + /** + * 以字典形式返回全部课程数据数据集合。字典的键值为[courseId, courseName]。 + * 白名单接口,登录用户均可访问。 + * + * @param filter 过滤对象。 + * @return 应答结果对象,包含的数据为 List>,map中包含两条记录,key的值分别是id和name,value对应具体数据。 + */ + @GetMapping("/listDictCourse") + public ResponseResult>> listDictCourse(Course filter) { + List resultList = courseService.getListByFilter(filter, null); + return ResponseResult.success(BeanQuery.select( + "courseId as id", "courseName as name").executeFrom(resultList)); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/CourseTransStatsController.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/CourseTransStatsController.java new file mode 100644 index 00000000..f71fd0e9 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/CourseTransStatsController.java @@ -0,0 +1,100 @@ +package com.orange.demo.app.controller; + +import com.github.pagehelper.page.PageMethod; +import com.orange.demo.app.model.*; +import com.orange.demo.app.service.*; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.constant.*; +import com.orange.demo.common.core.annotation.MyRequestBody; +import io.swagger.annotations.Api; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/** + * 课程统计操作控制器类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Api(tags = "课程统计管理接口") +@Slf4j +@RestController +@RequestMapping("/admin/app/courseTransStats") +public class CourseTransStatsController { + + @Autowired + private CourseTransStatsService courseTransStatsService; + + /** + * 列出符合过滤条件的课程统计列表。 + * + * @param courseTransStatsFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody CourseTransStats courseTransStatsFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, CourseTransStats.class); + List resultList = courseTransStatsService.getCourseTransStatsListWithRelation(courseTransStatsFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 分组列出符合过滤条件的课程统计列表。 + * + * @param courseTransStatsFilter 过滤对象。 + * @param groupParam 分组参数。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/listWithGroup") + public ResponseResult> listWithGroup( + @MyRequestBody CourseTransStats courseTransStatsFilter, + @MyRequestBody MyGroupParam groupParam, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + String orderBy = MyOrderParam.buildOrderBy(orderParam, CourseTransStats.class); + groupParam = MyGroupParam.buildGroupBy(groupParam, CourseTransStats.class); + if (groupParam == null) { + return ResponseResult.error( + ErrorCodeEnum.INVALID_ARGUMENT_FORMAT, "数据参数错误,分组参数不能为空!"); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + MyGroupCriteria criteria = groupParam.getGroupCriteria(); + List resultList = courseTransStatsService.getGroupedCourseTransStatsListWithRelation( + courseTransStatsFilter, criteria.getGroupSelect(), criteria.getGroupBy(), orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定课程统计对象详情。 + * + * @param statsId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long statsId) { + if (MyCommonUtil.existBlankArgument(statsId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + CourseTransStats courseTransStats = courseTransStatsService.getByIdWithRelation(statsId, MyRelationParam.full()); + if (courseTransStats == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(courseTransStats); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/GradeController.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/GradeController.java new file mode 100644 index 00000000..2f51f70e --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/GradeController.java @@ -0,0 +1,115 @@ +package com.orange.demo.app.controller; + +import com.orange.demo.app.model.*; +import com.orange.demo.app.service.*; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.util.MyCommonUtil; +import com.orange.demo.common.core.object.ResponseResult; +import com.orange.demo.common.core.annotation.MyRequestBody; +import com.orange.demo.common.core.validator.UpdateGroup; + +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import io.swagger.annotations.Api; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import cn.jimmyshi.beanquery.BeanQuery; + +import javax.validation.groups.Default; +import java.util.*; + +/** + * 年级操作控制器类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Api(tags = "年级管理接口") +@Slf4j +@RestController +@RequestMapping("/admin/app/grade") +public class GradeController { + + @Autowired + private GradeService gradeService; + + /** + * 新增年级数据。 + * + * @param grade 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @ApiOperationSupport(ignoreParameters = {"grade.gradeId"}) + @PostMapping("/add") + public ResponseResult add(@MyRequestBody Grade grade) { + String errorMessage = MyCommonUtil.getModelValidationError(grade); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + grade = gradeService.saveNew(grade); + return ResponseResult.success(grade.getGradeId()); + } + + /** + * 更新年级数据。 + * + * @param grade 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody Grade grade) { + String errorMessage = MyCommonUtil.getModelValidationError(grade, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + Grade originalGrade = gradeService.getById(grade.getGradeId()); + if (originalGrade == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + if (!gradeService.update(grade, originalGrade)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除年级数据。 + * + * @param gradeId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Integer gradeId) { + if (MyCommonUtil.existBlankArgument(gradeId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!gradeService.remove(gradeId)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 以字典形式返回全部年级数据集合。 + * 白名单接口,登录用户均可访问。 + * + * @return 应答结果对象,包含字典形式的数据集合。 + */ + @GetMapping("/listDictGrade") + public ResponseResult>> listDictGrade() { + List resultList = gradeService.getAllList(); + return ResponseResult.success(BeanQuery.select( + "gradeId as id", "gradeName as name").executeFrom(resultList)); + } + + /** + * 将当前字典表的数据重新加载到缓存中。 + * 由于缓存的数据更新,在add/update/delete等接口均有同步处理。因此该接口仅当同步过程中出现问题时, + * 可手工调用,或者每天晚上定时同步一次。 + */ + @GetMapping("/reloadCachedData") + public ResponseResult reloadCachedData() { + gradeService.reloadCachedData(true); + return ResponseResult.success(true); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/SchoolInfoController.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/SchoolInfoController.java new file mode 100644 index 00000000..48df39e7 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/SchoolInfoController.java @@ -0,0 +1,168 @@ +package com.orange.demo.app.controller; + +import cn.jimmyshi.beanquery.BeanQuery; +import com.github.pagehelper.page.PageMethod; +import com.orange.demo.app.model.*; +import com.orange.demo.app.service.*; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.constant.*; +import com.orange.demo.common.core.annotation.MyRequestBody; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import io.swagger.annotations.Api; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import javax.validation.groups.Default; + +/** + * 校区数据操作控制器类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Api(tags = "校区数据管理接口") +@Slf4j +@RestController +@RequestMapping("/admin/app/schoolInfo") +public class SchoolInfoController { + + @Autowired + private SchoolInfoService schoolInfoService; + + /** + * 新增校区数据数据。 + * + * @param schoolInfo 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @ApiOperationSupport(ignoreParameters = {"schoolInfo.userId"}) + @PostMapping("/add") + public ResponseResult add(@MyRequestBody SchoolInfo schoolInfo) { + String errorMessage = MyCommonUtil.getModelValidationError(schoolInfo); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = schoolInfoService.verifyRelatedData(schoolInfo, null); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + schoolInfo = schoolInfoService.saveNew(schoolInfo); + return ResponseResult.success(schoolInfo.getSchoolId()); + } + + /** + * 更新校区数据数据。 + * + * @param schoolInfo 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SchoolInfo schoolInfo) { + String errorMessage = MyCommonUtil.getModelValidationError(schoolInfo, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + SchoolInfo originalSchoolInfo = schoolInfoService.getById(schoolInfo.getSchoolId()); + if (originalSchoolInfo == null) { + //NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = schoolInfoService.verifyRelatedData(schoolInfo, originalSchoolInfo); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + if (!schoolInfoService.update(schoolInfo, originalSchoolInfo)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除校区数据数据。 + * + * @param schoolId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long schoolId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(schoolId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + SchoolInfo originalSchoolInfo = schoolInfoService.getById(schoolId); + if (originalSchoolInfo == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!schoolInfoService.remove(schoolId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的校区数据列表。 + * + * @param schoolInfoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody SchoolInfo schoolInfoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, SchoolInfo.class); + List resultList = schoolInfoService.getSchoolInfoListWithRelation(schoolInfoFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定校区数据对象详情。 + * + * @param schoolId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long schoolId) { + if (MyCommonUtil.existBlankArgument(schoolId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SchoolInfo schoolInfo = schoolInfoService.getByIdWithRelation(schoolId, MyRelationParam.full()); + if (schoolInfo == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(schoolInfo); + } + + /** + * 以字典形式返回全部校区数据数据集合。字典的键值为[schoolId, schoolName]。 + * 白名单接口,登录用户均可访问。 + * + * @param filter 过滤对象。 + * @return 应答结果对象,包含的数据为 List>,map中包含两条记录,key的值分别是id和name,value对应具体数据。 + */ + @GetMapping("/listDictSchoolInfo") + public ResponseResult>> listDictSchoolInfo(SchoolInfo filter) { + List resultList = schoolInfoService.getListByFilter(filter, null); + return ResponseResult.success(BeanQuery.select( + "schoolId as id", "schoolName as name").executeFrom(resultList)); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/StudentActionStatsController.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/StudentActionStatsController.java new file mode 100644 index 00000000..dee3ade9 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/StudentActionStatsController.java @@ -0,0 +1,100 @@ +package com.orange.demo.app.controller; + +import com.github.pagehelper.page.PageMethod; +import com.orange.demo.app.model.*; +import com.orange.demo.app.service.*; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.constant.*; +import com.orange.demo.common.core.annotation.MyRequestBody; +import io.swagger.annotations.Api; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/** + * 学生行为统计操作控制器类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Api(tags = "学生行为统计管理接口") +@Slf4j +@RestController +@RequestMapping("/admin/app/studentActionStats") +public class StudentActionStatsController { + + @Autowired + private StudentActionStatsService studentActionStatsService; + + /** + * 列出符合过滤条件的学生行为统计列表。 + * + * @param studentActionStatsFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody StudentActionStats studentActionStatsFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, StudentActionStats.class); + List resultList = studentActionStatsService.getStudentActionStatsListWithRelation(studentActionStatsFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 分组列出符合过滤条件的学生行为统计列表。 + * + * @param studentActionStatsFilter 过滤对象。 + * @param groupParam 分组参数。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/listWithGroup") + public ResponseResult> listWithGroup( + @MyRequestBody StudentActionStats studentActionStatsFilter, + @MyRequestBody MyGroupParam groupParam, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + String orderBy = MyOrderParam.buildOrderBy(orderParam, StudentActionStats.class); + groupParam = MyGroupParam.buildGroupBy(groupParam, StudentActionStats.class); + if (groupParam == null) { + return ResponseResult.error( + ErrorCodeEnum.INVALID_ARGUMENT_FORMAT, "数据参数错误,分组参数不能为空!"); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + MyGroupCriteria criteria = groupParam.getGroupCriteria(); + List resultList = studentActionStatsService.getGroupedStudentActionStatsListWithRelation( + studentActionStatsFilter, criteria.getGroupSelect(), criteria.getGroupBy(), orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定学生行为统计对象详情。 + * + * @param statsId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long statsId) { + if (MyCommonUtil.existBlankArgument(statsId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + StudentActionStats studentActionStats = studentActionStatsService.getByIdWithRelation(statsId, MyRelationParam.full()); + if (studentActionStats == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(studentActionStats); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/StudentActionTransController.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/StudentActionTransController.java new file mode 100644 index 00000000..0b5ec070 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/StudentActionTransController.java @@ -0,0 +1,159 @@ +package com.orange.demo.app.controller; + +import com.github.pagehelper.page.PageMethod; +import com.orange.demo.app.model.*; +import com.orange.demo.app.service.*; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.constant.*; +import com.orange.demo.common.core.annotation.MyRequestBody; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import io.swagger.annotations.Api; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import javax.validation.groups.Default; + +/** + * 学生行为流水操作控制器类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Api(tags = "学生行为流水管理接口") +@Slf4j +@RestController +@RequestMapping("/admin/app/studentActionTrans") +public class StudentActionTransController { + + @Autowired + private StudentActionTransService studentActionTransService; + + /** + * 新增学生行为流水数据。 + * + * @param studentActionTrans 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @ApiOperationSupport(ignoreParameters = { + "studentActionTrans.transId", + "studentActionTrans.createTimeStart", + "studentActionTrans.createTimeEnd"}) + @PostMapping("/add") + public ResponseResult add(@MyRequestBody StudentActionTrans studentActionTrans) { + String errorMessage = MyCommonUtil.getModelValidationError(studentActionTrans); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = studentActionTransService.verifyRelatedData(studentActionTrans, null); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + studentActionTrans = studentActionTransService.saveNew(studentActionTrans); + return ResponseResult.success(studentActionTrans.getTransId()); + } + + /** + * 更新学生行为流水数据。 + * + * @param studentActionTrans 更新对象。 + * @return 应答结果对象。 + */ + @ApiOperationSupport(ignoreParameters = { + "studentActionTrans.createTimeStart", + "studentActionTrans.createTimeEnd"}) + @PostMapping("/update") + public ResponseResult update(@MyRequestBody StudentActionTrans studentActionTrans) { + String errorMessage = MyCommonUtil.getModelValidationError(studentActionTrans, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + StudentActionTrans originalStudentActionTrans = studentActionTransService.getById(studentActionTrans.getTransId()); + if (originalStudentActionTrans == null) { + //NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = studentActionTransService.verifyRelatedData(studentActionTrans, originalStudentActionTrans); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + if (!studentActionTransService.update(studentActionTrans, originalStudentActionTrans)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除学生行为流水数据。 + * + * @param transId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long transId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(transId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + StudentActionTrans originalStudentActionTrans = studentActionTransService.getById(transId); + if (originalStudentActionTrans == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!studentActionTransService.remove(transId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的学生行为流水列表。 + * + * @param studentActionTransFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody StudentActionTrans studentActionTransFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, StudentActionTrans.class); + List resultList = studentActionTransService.getStudentActionTransListWithRelation(studentActionTransFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定学生行为流水对象详情。 + * + * @param transId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long transId) { + if (MyCommonUtil.existBlankArgument(transId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + StudentActionTrans studentActionTrans = studentActionTransService.getByIdWithRelation(transId, MyRelationParam.full()); + if (studentActionTrans == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(studentActionTrans); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/StudentClassController.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/StudentClassController.java new file mode 100644 index 00000000..c630169e --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/StudentClassController.java @@ -0,0 +1,426 @@ +package com.orange.demo.app.controller; + +import com.github.pagehelper.page.PageMethod; +import com.orange.demo.app.model.*; +import com.orange.demo.app.service.*; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.constant.*; +import com.orange.demo.common.core.annotation.MyRequestBody; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import io.swagger.annotations.Api; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import javax.validation.groups.Default; +import java.util.stream.Collectors; + +/** + * 班级数据操作控制器类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Api(tags = "班级数据管理接口") +@Slf4j +@RestController +@RequestMapping("/admin/app/studentClass") +public class StudentClassController { + + @Autowired + private StudentClassService studentClassService; + @Autowired + private CourseService courseService; + @Autowired + private StudentService studentService; + + /** + * 新增班级数据数据。 + * + * @param studentClass 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @ApiOperationSupport(ignoreParameters = {"studentClass.userId"}) + @PostMapping("/add") + public ResponseResult add(@MyRequestBody StudentClass studentClass) { + String errorMessage = MyCommonUtil.getModelValidationError(studentClass); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = studentClassService.verifyRelatedData(studentClass, null); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + studentClass = studentClassService.saveNew(studentClass); + return ResponseResult.success(studentClass.getClassId()); + } + + /** + * 更新班级数据数据。 + * + * @param studentClass 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody StudentClass studentClass) { + String errorMessage = MyCommonUtil.getModelValidationError(studentClass, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + StudentClass originalStudentClass = studentClassService.getById(studentClass.getClassId()); + if (originalStudentClass == null) { + //NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = studentClassService.verifyRelatedData(studentClass, originalStudentClass); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + if (!studentClassService.update(studentClass, originalStudentClass)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除班级数据数据。 + * + * @param classId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long classId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(classId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + StudentClass originalStudentClass = studentClassService.getById(classId); + if (originalStudentClass == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!studentClassService.remove(classId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的班级数据列表。 + * + * @param studentClassFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody StudentClass studentClassFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, StudentClass.class); + List resultList = studentClassService.getStudentClassListWithRelation(studentClassFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定班级数据对象详情。 + * + * @param classId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long classId) { + if (MyCommonUtil.existBlankArgument(classId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + StudentClass studentClass = studentClassService.getByIdWithRelation(classId, MyRelationParam.full()); + if (studentClass == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(studentClass); + } + + /** + * 列出不与指定班级数据存在多对多关系的 [课程数据] 列表数据。通常用于查看添加新 [课程数据] 对象的候选列表。 + * + * @param classId 主表关联字段。 + * @param courseFilter [课程数据] 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,返回符合条件的数据列表。 + */ + @PostMapping("/listNotInClassCourse") + public ResponseResult> listNotInClassCourse( + @MyRequestBody Long classId, + @MyRequestBody Course courseFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doClassCourseVerify(classId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, Course.class); + List resultList = + courseService.getNotInCourseListByClassId(classId, courseFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 列出与指定班级数据存在多对多关系的 [课程数据] 列表数据。 + * + * @param classId 主表关联字段。 + * @param courseFilter [课程数据] 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,返回符合条件的数据列表。 + */ + @PostMapping("/listClassCourse") + public ResponseResult> listClassCourse( + @MyRequestBody Long classId, + @MyRequestBody Course courseFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doClassCourseVerify(classId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, Course.class); + List resultList = + courseService.getCourseListByClassId(classId, courseFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + private ResponseResult doClassCourseVerify(Long classId) { + if (MyCommonUtil.existBlankArgument(classId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!studentClassService.existId(classId)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + return ResponseResult.success(); + } + + /** + * 批量添加班级数据和 [课程数据] 对象的多对多关联关系数据。 + * + * @param classId 主表主键Id。 + * @param classCourseList 关联对象列表。 + * @return 应答结果对象。 + */ + @PostMapping("/addClassCourse") + public ResponseResult addClassCourse( + @MyRequestBody Long classId, + @MyRequestBody(elementType = ClassCourse.class) List classCourseList) { + if (MyCommonUtil.existBlankArgument(classId, classCourseList)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + for (ClassCourse classCourse : classCourseList) { + String errorMessage = MyCommonUtil.getModelValidationError(classCourse); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + } + Set courseIdSet = + classCourseList.stream().map(ClassCourse::getCourseId).collect(Collectors.toSet()); + if (!studentClassService.existId(classId) + || !courseService.existUniqueKeyList("courseId", courseIdSet)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + studentClassService.addClassCourseList(classCourseList, classId); + return ResponseResult.success(); + } + + /** + * 更新指定班级数据和指定 [课程数据] 的多对多关联数据。 + * + * @param classCourse 对多对中间表对象。 + * @return 应答结果对象。 + */ + @PostMapping("/updateClassCourse") + public ResponseResult updateClassCourse(@MyRequestBody ClassCourse classCourse) { + String errorMessage = MyCommonUtil.getModelValidationError(classCourse); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + if (!studentClassService.updateClassCourse(classCourse)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 显示班级数据和指定 [课程数据] 的多对多关联详情数据。 + * + * @param classId 主表主键Id。 + * @param courseId 从表主键Id。 + * @return 应答结果对象,包括中间表详情。 + */ + @GetMapping("/viewClassCourse") + public ResponseResult viewClassCourse( + @RequestParam Long classId, @RequestParam Long courseId) { + if (MyCommonUtil.existBlankArgument(classId, courseId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + ClassCourse classCourse = studentClassService.getClassCourse(classId, courseId); + if (classCourse == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(classCourse); + } + + /** + * 移除指定班级数据和指定 [课程数据] 的多对多关联关系。 + * + * @param classId 主表主键Id。 + * @param courseId 从表主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/deleteClassCourse") + public ResponseResult deleteClassCourse( + @MyRequestBody Long classId, @MyRequestBody Long courseId) { + if (MyCommonUtil.existBlankArgument(classId, courseId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!studentClassService.removeClassCourse(classId, courseId)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 列出不与指定班级数据存在多对多关系的 [学生数据] 列表数据。通常用于查看添加新 [学生数据] 对象的候选列表。 + * + * @param classId 主表关联字段。 + * @param studentFilter [学生数据] 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,返回符合条件的数据列表。 + */ + @PostMapping("/listNotInClassStudent") + public ResponseResult> listNotInClassStudent( + @MyRequestBody Long classId, + @MyRequestBody Student studentFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doClassStudentVerify(classId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, Student.class); + List resultList = + studentService.getNotInStudentListByClassId(classId, studentFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 列出与指定班级数据存在多对多关系的 [学生数据] 列表数据。 + * + * @param classId 主表关联字段。 + * @param studentFilter [学生数据] 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,返回符合条件的数据列表。 + */ + @PostMapping("/listClassStudent") + public ResponseResult> listClassStudent( + @MyRequestBody Long classId, + @MyRequestBody Student studentFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doClassStudentVerify(classId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, Student.class); + List resultList = + studentService.getStudentListByClassId(classId, studentFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + private ResponseResult doClassStudentVerify(Long classId) { + if (MyCommonUtil.existBlankArgument(classId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!studentClassService.existId(classId)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + return ResponseResult.success(); + } + + /** + * 批量添加班级数据和 [学生数据] 对象的多对多关联关系数据。 + * + * @param classId 主表主键Id。 + * @param classStudentList 关联对象列表。 + * @return 应答结果对象。 + */ + @PostMapping("/addClassStudent") + public ResponseResult addClassStudent( + @MyRequestBody Long classId, + @MyRequestBody(elementType = ClassStudent.class) List classStudentList) { + if (MyCommonUtil.existBlankArgument(classId, classStudentList)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + for (ClassStudent classStudent : classStudentList) { + String errorMessage = MyCommonUtil.getModelValidationError(classStudent); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + } + Set studentIdSet = + classStudentList.stream().map(ClassStudent::getStudentId).collect(Collectors.toSet()); + if (!studentClassService.existId(classId) + || !studentService.existUniqueKeyList("studentId", studentIdSet)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + studentClassService.addClassStudentList(classStudentList, classId); + return ResponseResult.success(); + } + + /** + * 移除指定班级数据和指定 [学生数据] 的多对多关联关系。 + * + * @param classId 主表主键Id。 + * @param studentId 从表主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/deleteClassStudent") + public ResponseResult deleteClassStudent( + @MyRequestBody Long classId, @MyRequestBody Long studentId) { + if (MyCommonUtil.existBlankArgument(classId, studentId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!studentClassService.removeClassStudent(classId, studentId)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/StudentController.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/StudentController.java new file mode 100644 index 00000000..6f533dcb --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/controller/StudentController.java @@ -0,0 +1,180 @@ +package com.orange.demo.app.controller; + +import cn.jimmyshi.beanquery.BeanQuery; +import com.github.pagehelper.page.PageMethod; +import com.orange.demo.app.model.*; +import com.orange.demo.app.service.*; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.constant.*; +import com.orange.demo.common.core.annotation.MyRequestBody; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import io.swagger.annotations.Api; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import javax.validation.groups.Default; + +/** + * 学生数据操作控制器类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Api(tags = "学生数据管理接口") +@Slf4j +@RestController +@RequestMapping("/admin/app/student") +public class StudentController { + + @Autowired + private StudentService studentService; + + /** + * 新增学生数据数据。 + * + * @param student 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @ApiOperationSupport(ignoreParameters = { + "student.studentId", + "student.searchString", + "student.birthdayStart", + "student.birthdayEnd", + "student.registerTimeStart", + "student.registerTimeEnd"}) + @PostMapping("/add") + public ResponseResult add(@MyRequestBody Student student) { + String errorMessage = MyCommonUtil.getModelValidationError(student); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = studentService.verifyRelatedData(student, null); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + student = studentService.saveNew(student); + return ResponseResult.success(student.getStudentId()); + } + + /** + * 更新学生数据数据。 + * + * @param student 更新对象。 + * @return 应答结果对象。 + */ + @ApiOperationSupport(ignoreParameters = { + "student.searchString", + "student.birthdayStart", + "student.birthdayEnd", + "student.registerTimeStart", + "student.registerTimeEnd"}) + @PostMapping("/update") + public ResponseResult update(@MyRequestBody Student student) { + String errorMessage = MyCommonUtil.getModelValidationError(student, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + Student originalStudent = studentService.getById(student.getStudentId()); + if (originalStudent == null) { + //NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = studentService.verifyRelatedData(student, originalStudent); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + if (!studentService.update(student, originalStudent)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除学生数据数据。 + * + * @param studentId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long studentId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(studentId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + Student originalStudent = studentService.getById(studentId); + if (originalStudent == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!studentService.remove(studentId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的学生数据列表。 + * + * @param studentFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody Student studentFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, Student.class); + List resultList = studentService.getStudentListWithRelation(studentFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定学生数据对象详情。 + * + * @param studentId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long studentId) { + if (MyCommonUtil.existBlankArgument(studentId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + Student student = studentService.getByIdWithRelation(studentId, MyRelationParam.full()); + if (student == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(student); + } + + /** + * 以字典形式返回全部学生数据数据集合。字典的键值为[studentId, studentName]。 + * 白名单接口,登录用户均可访问。 + * + * @param filter 过滤对象。 + * @return 应答结果对象,包含的数据为 List>,map中包含两条记录,key的值分别是id和name,value对应具体数据。 + */ + @GetMapping("/listDictStudent") + public ResponseResult>> listDictStudent(Student filter) { + List resultList = studentService.getListByFilter(filter, null); + return ResponseResult.success(BeanQuery.select( + "studentId as id", "studentName as name").executeFrom(resultList)); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/AreaCodeMapper.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/AreaCodeMapper.java new file mode 100644 index 00000000..1f7bbf11 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/AreaCodeMapper.java @@ -0,0 +1,13 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.AreaCode; + +/** + * 行政区划数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-24 + */ +public interface AreaCodeMapper extends BaseDaoMapper { +} \ No newline at end of file diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/ClassCourseMapper.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/ClassCourseMapper.java new file mode 100644 index 00000000..95ca5b78 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/ClassCourseMapper.java @@ -0,0 +1,13 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.ClassCourse; + +/** + * 数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-24 + */ +public interface ClassCourseMapper extends BaseDaoMapper { +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/ClassStudentMapper.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/ClassStudentMapper.java new file mode 100644 index 00000000..3b465c45 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/ClassStudentMapper.java @@ -0,0 +1,13 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.ClassStudent; + +/** + * 数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-24 + */ +public interface ClassStudentMapper extends BaseDaoMapper { +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/CourseMapper.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/CourseMapper.java new file mode 100644 index 00000000..3265e928 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/CourseMapper.java @@ -0,0 +1,52 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.Course; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 课程数据数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-24 + */ +public interface CourseMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param courseFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getCourseList( + @Param("courseFilter") Course courseFilter, @Param("orderBy") String orderBy); + + /** + * 根据关联主表Id,获取关联从表数据列表。 + * + * @param classId 关联主表Id。 + * @param courseFilter 从表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 从表数据列表。 + */ + List getCourseListByClassId( + @Param("classId") Long classId, + @Param("courseFilter") Course courseFilter, + @Param("orderBy") String orderBy); + + /** + * 根据关联主表Id,获取关联从表中没有和主表建立关联关系的数据列表。 + * + * @param classId 关联主表Id。 + * @param courseFilter 过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 与主表没有建立关联的从表数据列表。 + */ + List getNotInCourseListByClassId( + @Param("classId") Long classId, + @Param("courseFilter") Course courseFilter, + @Param("orderBy") String orderBy); +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/CourseTransStatsMapper.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/CourseTransStatsMapper.java new file mode 100644 index 00000000..af1fa0cd --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/CourseTransStatsMapper.java @@ -0,0 +1,41 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.CourseTransStats; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 课程统计数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-24 + */ +public interface CourseTransStatsMapper extends BaseDaoMapper { + + /** + * 获取分组计算后的数据对象列表。 + * + * @param courseTransStatsFilter 主表过滤对象。 + * @param groupSelect 分组显示字段列表字符串,SELECT从句的参数。 + * @param groupBy 分组字段列表字符串,GROUP BY从句的参数。 + * @param orderBy 排序字符串,ORDER BY从句的参数。 + * @return 对象列表。 + */ + List getGroupedCourseTransStatsList( + @Param("courseTransStatsFilter") CourseTransStats courseTransStatsFilter, + @Param("groupSelect") String groupSelect, + @Param("groupBy") String groupBy, + @Param("orderBy") String orderBy); + + /** + * 获取过滤后的对象列表。 + * + * @param courseTransStatsFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getCourseTransStatsList( + @Param("courseTransStatsFilter") CourseTransStats courseTransStatsFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/GradeMapper.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/GradeMapper.java new file mode 100644 index 00000000..4f0011c9 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/GradeMapper.java @@ -0,0 +1,13 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.Grade; + +/** + * 年级数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-24 + */ +public interface GradeMapper extends BaseDaoMapper { +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/MaterialEditionMapper.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/MaterialEditionMapper.java new file mode 100644 index 00000000..2e9690e4 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/MaterialEditionMapper.java @@ -0,0 +1,13 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.MaterialEdition; + +/** + * 数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-24 + */ +public interface MaterialEditionMapper extends BaseDaoMapper { +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/SchoolInfoMapper.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/SchoolInfoMapper.java new file mode 100644 index 00000000..85a64e6c --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/SchoolInfoMapper.java @@ -0,0 +1,26 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.SchoolInfo; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 校区数据数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-24 + */ +public interface SchoolInfoMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param schoolInfoFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getSchoolInfoList( + @Param("schoolInfoFilter") SchoolInfo schoolInfoFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/StudentActionStatsMapper.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/StudentActionStatsMapper.java new file mode 100644 index 00000000..aadc4d19 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/StudentActionStatsMapper.java @@ -0,0 +1,41 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.StudentActionStats; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 学生行为统计数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-24 + */ +public interface StudentActionStatsMapper extends BaseDaoMapper { + + /** + * 获取分组计算后的数据对象列表。 + * + * @param studentActionStatsFilter 主表过滤对象。 + * @param groupSelect 分组显示字段列表字符串,SELECT从句的参数。 + * @param groupBy 分组字段列表字符串,GROUP BY从句的参数。 + * @param orderBy 排序字符串,ORDER BY从句的参数。 + * @return 对象列表。 + */ + List getGroupedStudentActionStatsList( + @Param("studentActionStatsFilter") StudentActionStats studentActionStatsFilter, + @Param("groupSelect") String groupSelect, + @Param("groupBy") String groupBy, + @Param("orderBy") String orderBy); + + /** + * 获取过滤后的对象列表。 + * + * @param studentActionStatsFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getStudentActionStatsList( + @Param("studentActionStatsFilter") StudentActionStats studentActionStatsFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/StudentActionTransMapper.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/StudentActionTransMapper.java new file mode 100644 index 00000000..dd0835b7 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/StudentActionTransMapper.java @@ -0,0 +1,26 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.StudentActionTrans; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 学生行为流水数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-24 + */ +public interface StudentActionTransMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param studentActionTransFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getStudentActionTransList( + @Param("studentActionTransFilter") StudentActionTrans studentActionTransFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/StudentClassMapper.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/StudentClassMapper.java new file mode 100644 index 00000000..6fe5a118 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/StudentClassMapper.java @@ -0,0 +1,26 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.StudentClass; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 班级数据数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-24 + */ +public interface StudentClassMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param studentClassFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getStudentClassList( + @Param("studentClassFilter") StudentClass studentClassFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/StudentMapper.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/StudentMapper.java new file mode 100644 index 00000000..ed0d8d90 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/StudentMapper.java @@ -0,0 +1,52 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.Student; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 学生数据数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-24 + */ +public interface StudentMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param studentFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getStudentList( + @Param("studentFilter") Student studentFilter, @Param("orderBy") String orderBy); + + /** + * 根据关联主表Id,获取关联从表数据列表。 + * + * @param classId 关联主表Id。 + * @param studentFilter 从表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 从表数据列表。 + */ + List getStudentListByClassId( + @Param("classId") Long classId, + @Param("studentFilter") Student studentFilter, + @Param("orderBy") String orderBy); + + /** + * 根据关联主表Id,获取关联从表中没有和主表建立关联关系的数据列表。 + * + * @param classId 关联主表Id。 + * @param studentFilter 过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 与主表没有建立关联的从表数据列表。 + */ + List getNotInStudentListByClassId( + @Param("classId") Long classId, + @Param("studentFilter") Student studentFilter, + @Param("orderBy") String orderBy); +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/AreaCodeMapper.xml b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/AreaCodeMapper.xml new file mode 100644 index 00000000..a65ab49a --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/AreaCodeMapper.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/ClassCourseMapper.xml b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/ClassCourseMapper.xml new file mode 100644 index 00000000..7fd02629 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/ClassCourseMapper.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/ClassStudentMapper.xml b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/ClassStudentMapper.xml new file mode 100644 index 00000000..7e0a0952 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/ClassStudentMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/CourseMapper.xml b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/CourseMapper.xml new file mode 100644 index 00000000..6140b090 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/CourseMapper.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_course.course_name LIKE #{safeCourseName} + + + AND zz_course.price >= #{courseFilter.priceStart} + + + AND zz_course.price <= #{courseFilter.priceEnd} + + + AND zz_course.difficulty = #{courseFilter.difficulty} + + + AND zz_course.grade_id = #{courseFilter.gradeId} + + + AND zz_course.subject_id = #{courseFilter.subjectId} + + + AND zz_course.class_hour >= #{courseFilter.classHourStart} + + + AND zz_course.class_hour <= #{courseFilter.classHourEnd} + + + AND zz_course.create_time >= #{courseFilter.createTimeStart} + + + AND zz_course.create_time <= #{courseFilter.createTimeEnd} + + + + + + SELECT * FROM zz_course + + + + + ORDER BY ${orderBy} + + + + + SELECT + zz_course.*, + zz_class_course.* + FROM + zz_course, + zz_class_course + + AND zz_class_course.class_id = #{classId} + AND zz_class_course.course_id = zz_course.course_id + + + + ORDER BY ${orderBy} + + + + + SELECT + zz_course.* + FROM + zz_course + + AND NOT EXISTS (SELECT * FROM zz_class_course + WHERE zz_class_course.class_id = #{classId} AND zz_class_course.course_id = zz_course.course_id) + + + + ORDER BY ${orderBy} + + + diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/CourseTransStatsMapper.xml b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/CourseTransStatsMapper.xml new file mode 100644 index 00000000..6eab763b --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/CourseTransStatsMapper.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + AND zz_course_trans_stats.stats_date >= #{courseTransStatsFilter.statsDateStart} + + + AND zz_course_trans_stats.stats_date <= #{courseTransStatsFilter.statsDateEnd} + + + AND zz_course_trans_stats.subject_id = #{courseTransStatsFilter.subjectId} + + + AND zz_course_trans_stats.grade_id = #{courseTransStatsFilter.gradeId} + + + + + + SELECT * FROM + (SELECT + SUM(student_attend_count) student_attend_count, + SUM(student_flower_amount) student_flower_amount, + SUM(student_flower_count) student_flower_count, + ${groupSelect} + FROM zz_course_trans_stats + + + + GROUP BY ${groupBy}) zz_course_trans_stats + + ORDER BY ${orderBy} + + + + + SELECT * FROM zz_course_trans_stats + + + + + ORDER BY ${orderBy} + + + diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/GradeMapper.xml b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/GradeMapper.xml new file mode 100644 index 00000000..0ed23888 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/GradeMapper.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/MaterialEditionMapper.xml b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/MaterialEditionMapper.xml new file mode 100644 index 00000000..75c26ef4 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/MaterialEditionMapper.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/SchoolInfoMapper.xml b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/SchoolInfoMapper.xml new file mode 100644 index 00000000..dd4c78aa --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/SchoolInfoMapper.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + AND zz_school_info.school_name LIKE #{safeSchoolName} + + + AND zz_school_info.province_id = #{schoolInfoFilter.provinceId} + + + AND zz_school_info.city_id = #{schoolInfoFilter.cityId} + + + + + + SELECT * FROM zz_school_info + + + + + ORDER BY ${orderBy} + + + diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/StudentActionStatsMapper.xml b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/StudentActionStatsMapper.xml new file mode 100644 index 00000000..e8e943c1 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/StudentActionStatsMapper.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_student_action_stats.stats_date >= #{studentActionStatsFilter.statsDateStart} + + + AND zz_student_action_stats.stats_date <= #{studentActionStatsFilter.statsDateEnd} + + + AND zz_student_action_stats.grade_id = #{studentActionStatsFilter.gradeId} + + + AND zz_student_action_stats.province_id = #{studentActionStatsFilter.provinceId} + + + AND zz_student_action_stats.city_id = #{studentActionStatsFilter.cityId} + + + + + + SELECT * FROM + (SELECT + SUM(buy_course_amount) buy_course_amount, + COUNT(buy_course_count) buy_course_count, + SUM(buy_video_amount) buy_video_amount, + COUNT(buy_video_count) buy_video_count, + SUM(buy_paper_amount) buy_paper_amount, + COUNT(buy_paper_count) buy_paper_count, + SUM(buy_flower_amount) buy_flower_amount, + COUNT(buy_flower_count) buy_flower_count, + SUM(recharge_coin_amount) recharge_coin_amount, + COUNT(recharge_coin_count) recharge_coin_count, + SUM(do_course_count) do_course_count, + SUM(watch_video_count) watch_video_count, + SUM(watch_video_total_second) watch_video_total_second, + SUM(do_exercise_count) do_exercise_count, + SUM(do_exercise_correct_count) do_exercise_correct_count, + ${groupSelect} + FROM zz_student_action_stats + + + + GROUP BY ${groupBy}) zz_student_action_stats + + ORDER BY ${orderBy} + + + + + SELECT * FROM zz_student_action_stats + + + + + ORDER BY ${orderBy} + + + diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/StudentActionTransMapper.xml b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/StudentActionTransMapper.xml new file mode 100644 index 00000000..55a8ac0c --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/StudentActionTransMapper.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_student_action_trans.student_id = #{studentActionTransFilter.studentId} + + + AND zz_student_action_trans.school_id = #{studentActionTransFilter.schoolId} + + + AND zz_student_action_trans.grade_id = #{studentActionTransFilter.gradeId} + + + AND zz_student_action_trans.action_type = #{studentActionTransFilter.actionType} + + + AND zz_student_action_trans.device_type = #{studentActionTransFilter.deviceType} + + + AND zz_student_action_trans.create_time >= #{studentActionTransFilter.createTimeStart} + + + AND zz_student_action_trans.create_time <= #{studentActionTransFilter.createTimeEnd} + + + + + + SELECT * FROM zz_student_action_trans + + + + + ORDER BY ${orderBy} + + + diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/StudentClassMapper.xml b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/StudentClassMapper.xml new file mode 100644 index 00000000..4d1372d4 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/StudentClassMapper.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + AND zz_class.class_name = #{studentClassFilter.className} + + + AND zz_class.school_id = #{studentClassFilter.schoolId} + + + AND zz_class.class_level = #{studentClassFilter.classLevel} + + + AND zz_class.status = ${@com.orange.demo.common.core.constant.GlobalDeletedFlag@NORMAL} + + + + SELECT * FROM zz_class + + + + + ORDER BY ${orderBy} + + + diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/StudentMapper.xml b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/StudentMapper.xml new file mode 100644 index 00000000..4fbee847 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/dao/mapper/StudentMapper.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_student.province_id = #{studentFilter.provinceId} + + + AND zz_student.city_id = #{studentFilter.cityId} + + + AND zz_student.district_id = #{studentFilter.districtId} + + + AND zz_student.birthday >= #{studentFilter.birthdayStart} + + + AND zz_student.birthday <= #{studentFilter.birthdayEnd} + + + AND zz_student.grade_id = #{studentFilter.gradeId} + + + AND zz_student.school_id = #{studentFilter.schoolId} + + + AND zz_student.register_time >= #{studentFilter.registerTimeStart} + + + AND zz_student.register_time <= #{studentFilter.registerTimeEnd} + + + AND zz_student.status = #{studentFilter.status} + + + + AND CONCAT(IFNULL(zz_student.login_mobile,''), IFNULL(zz_student.student_name,'')) LIKE #{safeSearchString} + + + + + + SELECT * FROM zz_student + + + + + ORDER BY ${orderBy} + + + + + SELECT + zz_student.* + FROM + zz_student, + zz_class_student + + AND zz_class_student.class_id = #{classId} + AND zz_class_student.student_id = zz_student.student_id + + + + ORDER BY ${orderBy} + + + + + SELECT + zz_student.* + FROM + zz_student + + AND NOT EXISTS (SELECT * FROM zz_class_student + WHERE zz_class_student.class_id = #{classId} AND zz_class_student.student_id = zz_student.student_id) + + + + ORDER BY ${orderBy} + + + diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/AreaCode.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/AreaCode.java new file mode 100644 index 00000000..44642e8c --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/AreaCode.java @@ -0,0 +1,48 @@ +package com.orange.demo.app.model; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.persistence.*; + +/** + * 行政区划实体对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +@ApiModel("行政区划实体对象") +@Data +@Table(name = "zz_area_code") +public class AreaCode { + + /** + * 行政区划主键Id + */ + @ApiModelProperty(value = "行政区划主键Id", required = true) + @Id + @Column(name = "area_id") + private Long areaId; + + /** + * 行政区划名称 + */ + @ApiModelProperty(value = "行政区划名称") + @Column(name = "area_name") + private String areaName; + + /** + * 行政区划级别 (1: 省级别 2: 市级别 3: 区级别) + */ + @ApiModelProperty(value = "行政区划级别") + @Column(name = "area_level") + private Integer areaLevel; + + /** + * 父级行政区划Id + */ + @ApiModelProperty(value = "父级行政区划Id") + @Column(name = "parent_id") + private Long parentId; +} \ No newline at end of file diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/ClassCourse.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/ClassCourse.java new file mode 100644 index 00000000..6ff4c756 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/ClassCourse.java @@ -0,0 +1,46 @@ +package com.orange.demo.app.model; + +import com.orange.demo.common.core.validator.UpdateGroup; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +/** + * ClassCourse实体对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +@ApiModel("ClassCourse实体对象") +@Data +@Table(name = "zz_class_course") +public class ClassCourse { + + /** + * 班级Id。 + */ + @ApiModelProperty(value = "班级Id", required = true) + @NotNull(message = "数据验证失败,班级Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "class_id") + private Long classId; + + /** + * 课程Id。 + */ + @ApiModelProperty(value = "课程Id", required = true) + @NotNull(message = "数据验证失败,课程Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "course_id") + private Long courseId; + + /** + * 课程顺序(数值越小越靠前)。 + */ + @ApiModelProperty(value = "课程顺序(数值越小越靠前)", required = true) + @NotNull(message = "数据验证失败,课程顺序(数值越小越靠前)不能为空!", groups = {UpdateGroup.class}) + @Column(name = "course_order") + private Integer courseOrder; +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/ClassStudent.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/ClassStudent.java new file mode 100644 index 00000000..6dee539d --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/ClassStudent.java @@ -0,0 +1,38 @@ +package com.orange.demo.app.model; + +import com.orange.demo.common.core.validator.UpdateGroup; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +/** + * ClassStudent实体对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +@ApiModel("ClassStudent实体对象") +@Data +@Table(name = "zz_class_student") +public class ClassStudent { + + /** + * 班级Id。 + */ + @ApiModelProperty(value = "班级Id", required = true) + @NotNull(message = "数据验证失败,班级Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "class_id") + private Long classId; + + /** + * 学生Id。 + */ + @ApiModelProperty(value = "学生Id", required = true) + @NotNull(message = "数据验证失败,学生Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "student_id") + private Long studentId; +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/Course.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/Course.java new file mode 100644 index 00000000..28c0a53e --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/Course.java @@ -0,0 +1,197 @@ +package com.orange.demo.app.model; + +import com.orange.demo.app.model.constant.CourseDifficult; +import com.orange.demo.application.common.constant.Subject; +import com.orange.demo.common.core.upload.UploadStoreTypeEnum; +import com.orange.demo.common.core.annotation.UploadFlagColumn; +import com.orange.demo.common.core.annotation.RelationDict; +import com.orange.demo.common.core.annotation.RelationConstDict; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.validator.ConstDictRef; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.Map; + +/** + * Course实体对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +@ApiModel("Course实体对象") +@Data +@Table(name = "zz_course") +public class Course { + + /** + * 主键Id。 + */ + @ApiModelProperty(value = "主键Id", required = true) + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "course_id") + private Long courseId; + + /** + * 课程名称。 + */ + @ApiModelProperty(value = "课程名称", required = true) + @NotBlank(message = "数据验证失败,课程名称不能为空!") + @Column(name = "course_name") + private String courseName; + + /** + * 课程价格。 + */ + @ApiModelProperty(value = "课程价格", required = true) + @NotNull(message = "数据验证失败,课程价格不能为空!") + private BigDecimal price; + + /** + * 课程描述。 + */ + @ApiModelProperty(value = "课程描述") + private String description; + + /** + * 课程难度(0: 容易 1: 普通 2: 很难)。 + */ + @ApiModelProperty(value = "课程难度(0: 容易 1: 普通 2: 很难)", required = true) + @NotNull(message = "数据验证失败,课程难度不能为空!") + @ConstDictRef(constDictClass = CourseDifficult.class, message = "数据验证失败,课程难度为无效值!") + private Integer difficulty; + + /** + * 年级Id。 + */ + @ApiModelProperty(value = "年级Id", required = true) + @NotNull(message = "数据验证失败,所属年级不能为空!") + @Column(name = "grade_id") + private Integer gradeId; + + /** + * 学科Id。 + */ + @ApiModelProperty(value = "学科Id", required = true) + @NotNull(message = "数据验证失败,所属学科不能为空!") + @ConstDictRef(constDictClass = Subject.class, message = "数据验证失败,所属学科为无效值!") + @Column(name = "subject_id") + private Integer subjectId; + + /** + * 课时数量。 + */ + @ApiModelProperty(value = "课时数量", required = true) + @NotNull(message = "数据验证失败,课时数量不能为空!") + @Column(name = "class_hour") + private Integer classHour; + + /** + * 多张课程图片地址。 + */ + @ApiModelProperty(value = "多张课程图片地址", required = true) + @UploadFlagColumn(storeType = UploadStoreTypeEnum.LOCAL_SYSTEM) + @NotBlank(message = "数据验证失败,课程图片不能为空!") + @Column(name = "picture_url") + private String pictureUrl; + + /** + * 创建用户Id。 + */ + @ApiModelProperty(value = "创建用户Id") + @Column(name = "create_user_id") + private Long createUserId; + + /** + * 创建时间。 + */ + @ApiModelProperty(value = "创建时间") + @Column(name = "create_time") + private Date createTime; + + /** + * 最后修改时间。 + */ + @ApiModelProperty(value = "最后修改时间") + @Column(name = "update_time") + private Date updateTime; + + /** + * price 范围过滤起始值(>=)。 + */ + @ApiModelProperty(value = "price 范围过滤起始值(>=)") + @Transient + private BigDecimal priceStart; + + /** + * price 范围过滤结束值(<=)。 + */ + @ApiModelProperty(value = "price 范围过滤结束值(<=)") + @Transient + private BigDecimal priceEnd; + + /** + * classHour 范围过滤起始值(>=)。 + */ + @ApiModelProperty(value = "classHour 范围过滤起始值(>=)") + @Transient + private Integer classHourStart; + + /** + * classHour 范围过滤结束值(<=)。 + */ + @ApiModelProperty(value = "classHour 范围过滤结束值(<=)") + @Transient + private Integer classHourEnd; + + /** + * createTime 范围过滤起始值(>=)。 + */ + @ApiModelProperty(value = "createTime 范围过滤起始值(>=)") + @Transient + private String createTimeStart; + + /** + * createTime 范围过滤结束值(<=)。 + */ + @ApiModelProperty(value = "createTime 范围过滤结束值(<=)") + @Transient + private String createTimeEnd; + + /** + * courseId 的多对多关联表数据对象。 + */ + @ApiModelProperty(hidden = true) + @Transient + private ClassCourse classCourse; + + @ApiModelProperty(hidden = true) + @RelationDict( + masterIdField = "gradeId", + slaveServiceName = "gradeService", + slaveModelClass = Grade.class, + slaveIdField = "gradeId", + slaveNameField = "gradeName") + @Transient + private Map gradeIdDictMap; + + @ApiModelProperty(hidden = true) + @RelationConstDict( + masterIdField = "difficulty", + constantDictClass = CourseDifficult.class) + @Transient + private Map difficultyDictMap; + + @ApiModelProperty(hidden = true) + @RelationConstDict( + masterIdField = "subjectId", + constantDictClass = Subject.class) + @Transient + private Map subjectIdDictMap; +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/CourseTransStats.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/CourseTransStats.java new file mode 100644 index 00000000..1577c58f --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/CourseTransStats.java @@ -0,0 +1,139 @@ +package com.orange.demo.app.model; + +import com.orange.demo.application.common.constant.Subject; +import com.orange.demo.common.core.annotation.RelationDict; +import com.orange.demo.common.core.annotation.RelationConstDict; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.validator.ConstDictRef; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Date; +import java.util.Map; + +/** + * CourseTransStats实体对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +@ApiModel("CourseTransStats实体对象") +@Data +@Table(name = "zz_course_trans_stats") +public class CourseTransStats { + + /** + * 主键Id。 + */ + @ApiModelProperty(value = "主键Id", required = true) + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "stats_id") + private Long statsId; + + /** + * 统计日期。 + */ + @ApiModelProperty(value = "统计日期", required = true) + @NotNull(message = "数据验证失败,统计日期不能为空!") + @Column(name = "stats_date") + private Date statsDate; + + /** + * 科目Id。 + */ + @ApiModelProperty(value = "科目Id", required = true) + @NotNull(message = "数据验证失败,所属科目不能为空!") + @ConstDictRef(constDictClass = Subject.class, message = "数据验证失败,所属科目为无效值!") + @Column(name = "subject_id") + private Integer subjectId; + + /** + * 年级Id。 + */ + @ApiModelProperty(value = "年级Id", required = true) + @NotNull(message = "数据验证失败,所属年级不能为空!") + @Column(name = "grade_id") + private Integer gradeId; + + /** + * 年级名称。 + */ + @ApiModelProperty(value = "年级名称") + @Column(name = "grade_name") + private String gradeName; + + /** + * 课程Id。 + */ + @ApiModelProperty(value = "课程Id", required = true) + @NotNull(message = "数据验证失败,课程Id不能为空!") + @Column(name = "course_id") + private Long courseId; + + /** + * 课程名称。 + */ + @ApiModelProperty(value = "课程名称") + @Column(name = "course_name") + private String courseName; + + /** + * 学生上课次数。 + */ + @ApiModelProperty(value = "学生上课次数", required = true) + @NotNull(message = "数据验证失败,上课次数不能为空!") + @Column(name = "student_attend_count") + private Integer studentAttendCount; + + /** + * 学生献花数量。 + */ + @ApiModelProperty(value = "学生献花数量", required = true) + @NotNull(message = "数据验证失败,献花数量不能为空!") + @Column(name = "student_flower_amount") + private Integer studentFlowerAmount; + + /** + * 学生献花次数。 + */ + @ApiModelProperty(value = "学生献花次数", required = true) + @NotNull(message = "数据验证失败,献花次数不能为空!") + @Column(name = "student_flower_count") + private Integer studentFlowerCount; + + /** + * statsDate 范围过滤起始值(>=)。 + */ + @ApiModelProperty(value = "statsDate 范围过滤起始值(>=)") + @Transient + private String statsDateStart; + + /** + * statsDate 范围过滤结束值(<=)。 + */ + @ApiModelProperty(value = "statsDate 范围过滤结束值(<=)") + @Transient + private String statsDateEnd; + + @ApiModelProperty(hidden = true) + @RelationDict( + masterIdField = "gradeId", + slaveServiceName = "gradeService", + slaveModelClass = Grade.class, + slaveIdField = "gradeId", + slaveNameField = "gradeName") + @Transient + private Map gradeIdDictMap; + + @ApiModelProperty(hidden = true) + @RelationConstDict( + masterIdField = "subjectId", + constantDictClass = Subject.class) + @Transient + private Map subjectIdDictMap; +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/Grade.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/Grade.java new file mode 100644 index 00000000..0d0a4859 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/Grade.java @@ -0,0 +1,48 @@ +package com.orange.demo.app.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.demo.common.core.annotation.DeletedFlagColumn; +import com.orange.demo.common.core.validator.UpdateGroup; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +/** + * Grade实体对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +@ApiModel("Grade实体对象") +@Data +@Table(name = "zz_grade") +public class Grade { + + /** + * 主键Id。 + */ + @ApiModelProperty(value = "主键Id", required = true) + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "grade_id") + private Integer gradeId; + + /** + * 年级名称。 + */ + @ApiModelProperty(value = "年级名称", required = true) + @NotBlank(message = "数据验证失败,年级名称不能为空!") + @Column(name = "grade_name") + private String gradeName; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @ApiModelProperty(hidden = true) + @JSONField(serialize = false) + @DeletedFlagColumn + private Integer status; +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/MaterialEdition.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/MaterialEdition.java new file mode 100644 index 00000000..59fe5b28 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/MaterialEdition.java @@ -0,0 +1,45 @@ +package com.orange.demo.app.model; + +import com.orange.demo.common.core.validator.UpdateGroup; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +/** + * MaterialEdition实体对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +@ApiModel("MaterialEdition实体对象") +@Data +@Table(name = "zz_material_edition") +public class MaterialEdition { + + /** + * 主键Id。 + */ + @ApiModelProperty(value = "主键Id", required = true) + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "edition_id") + private Integer editionId; + + /** + * 教材版本名称。 + */ + @ApiModelProperty(value = "教材版本名称", required = true) + @NotBlank(message = "数据验证失败,教材版本名称不能为空!") + @Column(name = "edition_name") + private String editionName; + + /** + * 是否正在使用(0:不是,1:是)。 + */ + @ApiModelProperty(value = "是否正在使用(0:不是,1:是)", required = true) + @NotNull(message = "数据验证失败,是否正在使用(0:不是,1:是)不能为空!") + private Integer status; +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/SchoolInfo.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/SchoolInfo.java new file mode 100644 index 00000000..806dbe06 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/SchoolInfo.java @@ -0,0 +1,76 @@ +package com.orange.demo.app.model; + +import com.orange.demo.common.core.annotation.RelationDict; +import com.orange.demo.common.core.validator.UpdateGroup; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Map; + +/** + * SchoolInfo实体对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +@ApiModel("SchoolInfo实体对象") +@Data +@Table(name = "zz_school_info") +public class SchoolInfo { + + /** + * 学校Id。 + */ + @ApiModelProperty(value = "学校Id", required = true) + @NotNull(message = "数据验证失败,学校Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "school_id") + private Long schoolId; + + /** + * 学校名称。 + */ + @ApiModelProperty(value = "学校名称", required = true) + @NotBlank(message = "数据验证失败,学校名称不能为空!") + @Column(name = "school_name") + private String schoolName; + + /** + * 所在省Id。 + */ + @ApiModelProperty(value = "所在省Id", required = true) + @NotNull(message = "数据验证失败,所在省份不能为空!") + @Column(name = "province_id") + private Long provinceId; + + /** + * 所在城市Id。 + */ + @ApiModelProperty(value = "所在城市Id", required = true) + @NotNull(message = "数据验证失败,所在城市不能为空!") + @Column(name = "city_id") + private Long cityId; + + @ApiModelProperty(hidden = true) + @RelationDict( + masterIdField = "provinceId", + slaveServiceName = "areaCodeService", + slaveModelClass = AreaCode.class, + slaveIdField = "areaId", + slaveNameField = "areaName") + @Transient + private Map provinceIdDictMap; + + @ApiModelProperty(hidden = true) + @RelationDict( + masterIdField = "cityId", + slaveServiceName = "areaCodeService", + slaveModelClass = AreaCode.class, + slaveIdField = "areaId", + slaveNameField = "areaName") + @Transient + private Map cityIdDictMap; +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/Student.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/Student.java new file mode 100644 index 00000000..3e7bbba5 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/Student.java @@ -0,0 +1,255 @@ +package com.orange.demo.app.model; + +import com.orange.demo.application.common.constant.Gender; +import com.orange.demo.application.common.constant.ExpLevel; +import com.orange.demo.application.common.constant.StudentStatus; +import com.orange.demo.common.core.annotation.RelationDict; +import com.orange.demo.common.core.annotation.RelationConstDict; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.validator.ConstDictRef; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Date; +import java.util.Map; + +/** + * Student实体对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +@ApiModel("Student实体对象") +@Data +@Table(name = "zz_student") +public class Student { + + /** + * 学生Id。 + */ + @ApiModelProperty(value = "学生Id", required = true) + @NotNull(message = "数据验证失败,学生Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "student_id") + private Long studentId; + + /** + * 登录手机。 + */ + @ApiModelProperty(value = "登录手机", required = true) + @NotBlank(message = "数据验证失败,手机号码不能为空!") + @Column(name = "login_mobile") + private String loginMobile; + + /** + * 学生姓名。 + */ + @ApiModelProperty(value = "学生姓名", required = true) + @NotBlank(message = "数据验证失败,学生姓名不能为空!") + @Column(name = "student_name") + private String studentName; + + /** + * 所在省份Id。 + */ + @ApiModelProperty(value = "所在省份Id", required = true) + @NotNull(message = "数据验证失败,所在省份不能为空!") + @Column(name = "province_id") + private Long provinceId; + + /** + * 所在城市Id。 + */ + @ApiModelProperty(value = "所在城市Id", required = true) + @NotNull(message = "数据验证失败,所在城市不能为空!") + @Column(name = "city_id") + private Long cityId; + + /** + * 区县Id。 + */ + @ApiModelProperty(value = "区县Id", required = true) + @NotNull(message = "数据验证失败,所在区县不能为空!") + @Column(name = "district_id") + private Long districtId; + + /** + * 学生性别 (0: 女生 1: 男生)。 + */ + @ApiModelProperty(value = "学生性别 (0: 女生 1: 男生)", required = true) + @NotNull(message = "数据验证失败,学生性别不能为空!") + @ConstDictRef(constDictClass = Gender.class, message = "数据验证失败,学生性别为无效值!") + private Integer gender; + + /** + * 生日。 + */ + @ApiModelProperty(value = "生日", required = true) + @NotNull(message = "数据验证失败,出生日期不能为空!") + private Date birthday; + + /** + * 经验等级 (0: 初级 1: 中级 2: 高级 3: 资深)。 + */ + @ApiModelProperty(value = "经验等级 (0: 初级 1: 中级 2: 高级 3: 资深)", required = true) + @NotNull(message = "数据验证失败,经验等级不能为空!") + @ConstDictRef(constDictClass = ExpLevel.class, message = "数据验证失败,经验等级为无效值!") + @Column(name = "experience_level") + private Integer experienceLevel; + + /** + * 总共充值学币数量。 + */ + @ApiModelProperty(value = "总共充值学币数量", required = true) + @NotNull(message = "数据验证失败,充值学币不能为空!", groups = {UpdateGroup.class}) + @Column(name = "total_coin") + private Integer totalCoin; + + /** + * 可用学币数量。 + */ + @ApiModelProperty(value = "可用学币数量", required = true) + @NotNull(message = "数据验证失败,剩余学币不能为空!", groups = {UpdateGroup.class}) + @Column(name = "left_coin") + private Integer leftCoin; + + /** + * 年级Id。 + */ + @ApiModelProperty(value = "年级Id", required = true) + @NotNull(message = "数据验证失败,年级不能为空!") + @Column(name = "grade_id") + private Integer gradeId; + + /** + * 校区Id。 + */ + @ApiModelProperty(value = "校区Id", required = true) + @NotNull(message = "数据验证失败,所属校区不能为空!") + @Column(name = "school_id") + private Long schoolId; + + /** + * 注册时间。 + */ + @ApiModelProperty(value = "注册时间") + @Column(name = "register_time") + private Date registerTime; + + /** + * 学生状态 (0: 正常 1: 锁定 2: 注销)。 + */ + @ApiModelProperty(value = "学生状态 (0: 正常 1: 锁定 2: 注销)", required = true) + @NotNull(message = "数据验证失败,学生状态不能为空!", groups = {UpdateGroup.class}) + @ConstDictRef(constDictClass = StudentStatus.class, message = "数据验证失败,学生状态为无效值!") + private Integer status; + + /** + * birthday 范围过滤起始值(>=)。 + */ + @ApiModelProperty(value = "birthday 范围过滤起始值(>=)") + @Transient + private String birthdayStart; + + /** + * birthday 范围过滤结束值(<=)。 + */ + @ApiModelProperty(value = "birthday 范围过滤结束值(<=)") + @Transient + private String birthdayEnd; + + /** + * registerTime 范围过滤起始值(>=)。 + */ + @ApiModelProperty(value = "registerTime 范围过滤起始值(>=)") + @Transient + private String registerTimeStart; + + /** + * registerTime 范围过滤结束值(<=)。 + */ + @ApiModelProperty(value = "registerTime 范围过滤结束值(<=)") + @Transient + private String registerTimeEnd; + + /** + * login_mobile / student_name LIKE搜索字符串。 + */ + @ApiModelProperty(value = "LIKE模糊搜索字符串") + @Transient + private String searchString; + + @ApiModelProperty(hidden = true) + @RelationDict( + masterIdField = "provinceId", + slaveServiceName = "areaCodeService", + slaveModelClass = AreaCode.class, + slaveIdField = "areaId", + slaveNameField = "areaName") + @Transient + private Map provinceIdDictMap; + + @ApiModelProperty(hidden = true) + @RelationDict( + masterIdField = "cityId", + slaveServiceName = "areaCodeService", + slaveModelClass = AreaCode.class, + slaveIdField = "areaId", + slaveNameField = "areaName") + @Transient + private Map cityIdDictMap; + + @ApiModelProperty(hidden = true) + @RelationDict( + masterIdField = "districtId", + slaveServiceName = "areaCodeService", + slaveModelClass = AreaCode.class, + slaveIdField = "areaId", + slaveNameField = "areaName") + @Transient + private Map districtIdDictMap; + + @ApiModelProperty(hidden = true) + @RelationDict( + masterIdField = "gradeId", + slaveServiceName = "gradeService", + slaveModelClass = Grade.class, + slaveIdField = "gradeId", + slaveNameField = "gradeName") + @Transient + private Map gradeIdDictMap; + + @ApiModelProperty(hidden = true) + @RelationDict( + masterIdField = "schoolId", + slaveServiceName = "schoolInfoService", + slaveModelClass = SchoolInfo.class, + slaveIdField = "schoolId", + slaveNameField = "schoolName") + @Transient + private Map schoolIdDictMap; + + @ApiModelProperty(hidden = true) + @RelationConstDict( + masterIdField = "gender", + constantDictClass = Gender.class) + @Transient + private Map genderDictMap; + + @ApiModelProperty(hidden = true) + @RelationConstDict( + masterIdField = "experienceLevel", + constantDictClass = ExpLevel.class) + @Transient + private Map experienceLevelDictMap; + + @ApiModelProperty(hidden = true) + @RelationConstDict( + masterIdField = "status", + constantDictClass = StudentStatus.class) + @Transient + private Map statusDictMap; +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/StudentActionStats.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/StudentActionStats.java new file mode 100644 index 00000000..32baafbf --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/StudentActionStats.java @@ -0,0 +1,236 @@ +package com.orange.demo.app.model; + +import com.orange.demo.common.core.annotation.RelationDict; +import com.orange.demo.common.core.validator.UpdateGroup; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Date; +import java.util.Map; + +/** + * StudentActionStats实体对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +@ApiModel("StudentActionStats实体对象") +@Data +@Table(name = "zz_student_action_stats") +public class StudentActionStats { + + /** + * 主键Id。 + */ + @ApiModelProperty(value = "主键Id", required = true) + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "stats_id") + private Long statsId; + + /** + * 统计日期。 + */ + @ApiModelProperty(value = "统计日期", required = true) + @NotNull(message = "数据验证失败,统计日期不能为空!") + @Column(name = "stats_date") + private Date statsDate; + + /** + * 统计小时。 + */ + @ApiModelProperty(value = "统计小时") + @Column(name = "stats_month") + private Date statsMonth; + + /** + * 年级Id。 + */ + @ApiModelProperty(value = "年级Id", required = true) + @NotNull(message = "数据验证失败,所属年级不能为空!") + @Column(name = "grade_id") + private Integer gradeId; + + /** + * 学生所在省Id。 + */ + @ApiModelProperty(value = "学生所在省Id", required = true) + @NotNull(message = "数据验证失败,所在省份不能为空!") + @Column(name = "province_id") + private Long provinceId; + + /** + * 学生所在城市Id。 + */ + @ApiModelProperty(value = "学生所在城市Id", required = true) + @NotNull(message = "数据验证失败,所在城市不能为空!", groups = {UpdateGroup.class}) + @Column(name = "city_id") + private Long cityId; + + /** + * 购课学币数量。 + */ + @ApiModelProperty(value = "购课学币数量", required = true) + @NotNull(message = "数据验证失败,购课学币数量不能为空!", groups = {UpdateGroup.class}) + @Column(name = "buy_course_amount") + private Integer buyCourseAmount; + + /** + * 购买课程次数。 + */ + @ApiModelProperty(value = "购买课程次数", required = true) + @NotNull(message = "数据验证失败,购买课程次数不能为空!", groups = {UpdateGroup.class}) + @Column(name = "buy_course_count") + private Integer buyCourseCount; + + /** + * 购买视频学币数量。 + */ + @ApiModelProperty(value = "购买视频学币数量", required = true) + @NotNull(message = "数据验证失败,购买视频学币数量不能为空!", groups = {UpdateGroup.class}) + @Column(name = "buy_video_amount") + private Integer buyVideoAmount; + + /** + * 购买视频次数。 + */ + @ApiModelProperty(value = "购买视频次数", required = true) + @NotNull(message = "数据验证失败,购买视频次数不能为空!", groups = {UpdateGroup.class}) + @Column(name = "buy_video_count") + private Integer buyVideoCount; + + /** + * 购买作业学币数量。 + */ + @ApiModelProperty(value = "购买作业学币数量", required = true) + @NotNull(message = "数据验证失败,购买作业学币数量不能为空!", groups = {UpdateGroup.class}) + @Column(name = "buy_paper_amount") + private Integer buyPaperAmount; + + /** + * 购买作业次数。 + */ + @ApiModelProperty(value = "购买作业次数", required = true) + @NotNull(message = "数据验证失败,购买作业次数不能为空!", groups = {UpdateGroup.class}) + @Column(name = "buy_paper_count") + private Integer buyPaperCount; + + /** + * 购买献花数量。 + */ + @ApiModelProperty(value = "购买献花数量", required = true) + @NotNull(message = "数据验证失败,购买献花数量不能为空!", groups = {UpdateGroup.class}) + @Column(name = "buy_flower_amount") + private Integer buyFlowerAmount; + + /** + * 购买献花次数。 + */ + @ApiModelProperty(value = "购买献花次数", required = true) + @NotNull(message = "数据验证失败,购买献花次数不能为空!", groups = {UpdateGroup.class}) + @Column(name = "buy_flower_count") + private Integer buyFlowerCount; + + /** + * 充值学币数量。 + */ + @ApiModelProperty(value = "充值学币数量", required = true) + @NotNull(message = "数据验证失败,充值学币数量不能为空!", groups = {UpdateGroup.class}) + @Column(name = "recharge_coin_amount") + private Integer rechargeCoinAmount; + + /** + * 充值学币次数。 + */ + @ApiModelProperty(value = "充值学币次数", required = true) + @NotNull(message = "数据验证失败,充值学币次数不能为空!", groups = {UpdateGroup.class}) + @Column(name = "recharge_coin_count") + private Integer rechargeCoinCount; + + /** + * 线下课程上课次数。 + */ + @ApiModelProperty(value = "线下课程上课次数", required = true) + @NotNull(message = "数据验证失败,线下课程上课次数不能为空!") + @Column(name = "do_course_count") + private Integer doCourseCount; + + /** + * 观看视频次数。 + */ + @ApiModelProperty(value = "观看视频次数", required = true) + @NotNull(message = "数据验证失败,观看视频次数不能为空!", groups = {UpdateGroup.class}) + @Column(name = "watch_video_count") + private Integer watchVideoCount; + + /** + * 购买献花消费学币数量。 + */ + @ApiModelProperty(value = "购买献花消费学币数量", required = true) + @NotNull(message = "数据验证失败,购买献花消费学币数量不能为空!") + @Column(name = "watch_video_total_second") + private Integer watchVideoTotalSecond; + + /** + * 做题数量。 + */ + @ApiModelProperty(value = "做题数量", required = true) + @NotNull(message = "数据验证失败,做题数量不能为空!", groups = {UpdateGroup.class}) + @Column(name = "do_exercise_count") + private Integer doExerciseCount; + + /** + * 做题正确的数量。 + */ + @ApiModelProperty(value = "做题正确的数量", required = true) + @NotNull(message = "数据验证失败,做题正确的数量不能为空!", groups = {UpdateGroup.class}) + @Column(name = "do_exercise_correct_count") + private Integer doExerciseCorrectCount; + + /** + * statsDate 范围过滤起始值(>=)。 + */ + @ApiModelProperty(value = "statsDate 范围过滤起始值(>=)") + @Transient + private String statsDateStart; + + /** + * statsDate 范围过滤结束值(<=)。 + */ + @ApiModelProperty(value = "statsDate 范围过滤结束值(<=)") + @Transient + private String statsDateEnd; + + @ApiModelProperty(hidden = true) + @RelationDict( + masterIdField = "gradeId", + slaveServiceName = "gradeService", + slaveModelClass = Grade.class, + slaveIdField = "gradeId", + slaveNameField = "gradeName") + @Transient + private Map gradeIdDictMap; + + @ApiModelProperty(hidden = true) + @RelationDict( + masterIdField = "provinceId", + slaveServiceName = "areaCodeService", + slaveModelClass = AreaCode.class, + slaveIdField = "areaId", + slaveNameField = "areaName") + @Transient + private Map provinceIdDictMap; + + @ApiModelProperty(hidden = true) + @RelationDict( + masterIdField = "cityId", + slaveServiceName = "areaCodeService", + slaveModelClass = AreaCode.class, + slaveIdField = "areaId", + slaveNameField = "areaName") + @Transient + private Map cityIdDictMap; +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/StudentActionTrans.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/StudentActionTrans.java new file mode 100644 index 00000000..dff3cd0b --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/StudentActionTrans.java @@ -0,0 +1,192 @@ +package com.orange.demo.app.model; + +import com.orange.demo.application.common.constant.StudentActionType; +import com.orange.demo.application.common.constant.DeviceType; +import com.orange.demo.common.core.annotation.RelationDict; +import com.orange.demo.common.core.annotation.RelationConstDict; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.validator.ConstDictRef; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Date; +import java.util.Map; + +/** + * StudentActionTrans实体对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +@ApiModel("StudentActionTrans实体对象") +@Data +@Table(name = "zz_student_action_trans") +public class StudentActionTrans { + + /** + * 主键Id。 + */ + @ApiModelProperty(value = "主键Id", required = true) + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "trans_id") + private Long transId; + + /** + * 学生Id。 + */ + @ApiModelProperty(value = "学生Id", required = true) + @NotNull(message = "数据验证失败,学生Id不能为空!") + @Column(name = "student_id") + private Long studentId; + + /** + * 学生名称。 + */ + @ApiModelProperty(value = "学生名称", required = true) + @NotBlank(message = "数据验证失败,学生名称不能为空!") + @Column(name = "student_name") + private String studentName; + + /** + * 学生校区。 + */ + @ApiModelProperty(value = "学生校区", required = true) + @NotNull(message = "数据验证失败,学生校区不能为空!") + @Column(name = "school_id") + private Long schoolId; + + /** + * 年级Id。 + */ + @ApiModelProperty(value = "年级Id", required = true) + @NotNull(message = "数据验证失败,学生年级不能为空!") + @Column(name = "grade_id") + private Integer gradeId; + + /** + * 行为类型(0: 充值 1: 购课 2: 上课签到 3: 上课签退 4: 看视频课 5: 做作业 6: 刷题 7: 献花)。 + */ + @ApiModelProperty(value = "行为类型(0: 充值 1: 购课 2: 上课签到 3: 上课签退 4: 看视频课 5: 做作业 6: 刷题 7: 献花)", required = true) + @NotNull(message = "数据验证失败,行为类型不能为空!") + @ConstDictRef(constDictClass = StudentActionType.class, message = "数据验证失败,行为类型为无效值!") + @Column(name = "action_type") + private Integer actionType; + + /** + * 设备类型(0: iOS 1: Android 2: PC)。 + */ + @ApiModelProperty(value = "设备类型(0: iOS 1: Android 2: PC)", required = true) + @NotNull(message = "数据验证失败,设备类型不能为空!") + @ConstDictRef(constDictClass = DeviceType.class, message = "数据验证失败,设备类型为无效值!") + @Column(name = "device_type") + private Integer deviceType; + + /** + * 看视频秒数。 + */ + @ApiModelProperty(value = "看视频秒数") + @Column(name = "watch_video_seconds") + private Integer watchVideoSeconds; + + /** + * 购买献花数量。 + */ + @ApiModelProperty(value = "购买献花数量") + @Column(name = "flower_count") + private Integer flowerCount; + + /** + * 购买作业数量。 + */ + @ApiModelProperty(value = "购买作业数量") + @Column(name = "paper_count") + private Integer paperCount; + + /** + * 购买视频数量。 + */ + @ApiModelProperty(value = "购买视频数量") + @Column(name = "video_count") + private Integer videoCount; + + /** + * 购买课程数量。 + */ + @ApiModelProperty(value = "购买课程数量") + @Column(name = "course_count") + private Integer courseCount; + + /** + * 充值学币数量。 + */ + @ApiModelProperty(value = "充值学币数量") + @Column(name = "coin_count") + private Integer coinCount; + + /** + * 做题是否正确标记。 + */ + @ApiModelProperty(value = "做题是否正确标记") + @Column(name = "exercise_correct_flag") + private Integer exerciseCorrectFlag; + + /** + * 发生时间。 + */ + @ApiModelProperty(value = "发生时间", required = true) + @NotNull(message = "数据验证失败,发生时间不能为空!") + @Column(name = "create_time") + private Date createTime; + + /** + * createTime 范围过滤起始值(>=)。 + */ + @ApiModelProperty(value = "createTime 范围过滤起始值(>=)") + @Transient + private String createTimeStart; + + /** + * createTime 范围过滤结束值(<=)。 + */ + @ApiModelProperty(value = "createTime 范围过滤结束值(<=)") + @Transient + private String createTimeEnd; + + @ApiModelProperty(hidden = true) + @RelationDict( + masterIdField = "schoolId", + slaveServiceName = "schoolInfoService", + slaveModelClass = SchoolInfo.class, + slaveIdField = "schoolId", + slaveNameField = "schoolName") + @Transient + private Map schoolIdDictMap; + + @ApiModelProperty(hidden = true) + @RelationDict( + masterIdField = "gradeId", + slaveServiceName = "gradeService", + slaveModelClass = Grade.class, + slaveIdField = "gradeId", + slaveNameField = "gradeName") + @Transient + private Map gradeIdDictMap; + + @ApiModelProperty(hidden = true) + @RelationConstDict( + masterIdField = "actionType", + constantDictClass = StudentActionType.class) + @Transient + private Map actionTypeDictMap; + + @ApiModelProperty(hidden = true) + @RelationConstDict( + masterIdField = "deviceType", + constantDictClass = DeviceType.class) + @Transient + private Map deviceTypeDictMap; +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/StudentClass.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/StudentClass.java new file mode 100644 index 00000000..c8cc313a --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/StudentClass.java @@ -0,0 +1,128 @@ +package com.orange.demo.app.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.demo.app.model.constant.ClassLevel; +import com.orange.demo.common.core.annotation.RelationDict; +import com.orange.demo.common.core.annotation.RelationConstDict; +import com.orange.demo.common.core.annotation.DeletedFlagColumn; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.validator.ConstDictRef; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Date; +import java.util.Map; + +/** + * StudentClass实体对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +@ApiModel("StudentClass实体对象") +@Data +@Table(name = "zz_class") +public class StudentClass { + + /** + * 班级Id。 + */ + @ApiModelProperty(value = "班级Id", required = true) + @NotNull(message = "数据验证失败,班级Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "class_id") + private Long classId; + + /** + * 班级名称。 + */ + @ApiModelProperty(value = "班级名称", required = true) + @NotBlank(message = "数据验证失败,班级名称不能为空!") + @Column(name = "class_name") + private String className; + + /** + * 学校Id。 + */ + @ApiModelProperty(value = "学校Id", required = true) + @NotNull(message = "数据验证失败,所属校区不能为空!") + @Column(name = "school_id") + private Long schoolId; + + /** + * 学生班长Id。 + */ + @ApiModelProperty(value = "学生班长Id", required = true) + @NotNull(message = "数据验证失败,学生班长不能为空!") + @Column(name = "leader_id") + private Long leaderId; + + /** + * 已完成课时数量。 + */ + @ApiModelProperty(value = "已完成课时数量", required = true) + @NotNull(message = "数据验证失败,已完成课时不能为空!", groups = {UpdateGroup.class}) + @Column(name = "finish_class_hour") + private Integer finishClassHour; + + /** + * 班级级别(0: 初级班 1: 培优班 2: 冲刺提分班 3: 竞赛班)。 + */ + @ApiModelProperty(value = "班级级别(0: 初级班 1: 培优班 2: 冲刺提分班 3: 竞赛班)", required = true) + @NotNull(message = "数据验证失败,班级级别不能为空!") + @ConstDictRef(constDictClass = ClassLevel.class, message = "数据验证失败,班级级别为无效值!") + @Column(name = "class_level") + private Integer classLevel; + + /** + * 创建用户。 + */ + @ApiModelProperty(value = "创建用户") + @Column(name = "create_user_id") + private Long createUserId; + + /** + * 班级创建时间。 + */ + @ApiModelProperty(value = "班级创建时间") + @Column(name = "create_time") + private Date createTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @ApiModelProperty(hidden = true) + @JSONField(serialize = false) + @DeletedFlagColumn + private Integer status; + + @ApiModelProperty(hidden = true) + @RelationDict( + masterIdField = "schoolId", + slaveServiceName = "schoolInfoService", + slaveModelClass = SchoolInfo.class, + slaveIdField = "schoolId", + slaveNameField = "schoolName") + @Transient + private Map schoolIdDictMap; + + @ApiModelProperty(hidden = true) + @RelationDict( + masterIdField = "leaderId", + slaveServiceName = "studentService", + slaveModelClass = Student.class, + slaveIdField = "studentId", + slaveNameField = "studentName") + @Transient + private Map leaderIdDictMap; + + @ApiModelProperty(hidden = true) + @RelationConstDict( + masterIdField = "classLevel", + constantDictClass = ClassLevel.class) + @Transient + private Map classLevelDictMap; +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/constant/ClassLevel.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/constant/ClassLevel.java new file mode 100644 index 00000000..83711f1b --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/constant/ClassLevel.java @@ -0,0 +1,49 @@ +package com.orange.demo.app.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 班级级别常量字典对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +public final class ClassLevel { + + /** + * 初级班。 + */ + public static final int NORMAL = 0; + /** + * 中级班。 + */ + public static final int MIDDLE = 1; + /** + * 高级班。 + */ + public static final int HIGH = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(NORMAL, "初级班"); + DICT_MAP.put(MIDDLE, "中级班"); + DICT_MAP.put(HIGH, "高级班"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private ClassLevel() { + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/constant/ClassStatus.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/constant/ClassStatus.java new file mode 100644 index 00000000..1d24a0fe --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/constant/ClassStatus.java @@ -0,0 +1,44 @@ +package com.orange.demo.app.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 班级状态常量字典对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +public final class ClassStatus { + + /** + * 正常。 + */ + public static final int NORAML = 1; + /** + * 解散。 + */ + public static final int DELETED = -1; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(NORAML, "正常"); + DICT_MAP.put(DELETED, "解散"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private ClassStatus() { + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/constant/CourseDifficult.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/constant/CourseDifficult.java new file mode 100644 index 00000000..485905ae --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/model/constant/CourseDifficult.java @@ -0,0 +1,49 @@ +package com.orange.demo.app.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 课程难度常量字典对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +public final class CourseDifficult { + + /** + * 容易。 + */ + public static final int NORMAL = 0; + /** + * 普通。 + */ + public static final int MIDDLE = 1; + /** + * 困难。 + */ + public static final int HIGH = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(NORMAL, "容易"); + DICT_MAP.put(MIDDLE, "普通"); + DICT_MAP.put(HIGH, "困难"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private CourseDifficult() { + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/AreaCodeService.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/AreaCodeService.java new file mode 100644 index 00000000..3d539da7 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/AreaCodeService.java @@ -0,0 +1,57 @@ +package com.orange.demo.app.service; + +import com.orange.demo.app.dao.AreaCodeMapper; +import com.orange.demo.app.model.AreaCode; +import com.orange.demo.common.core.cache.MapTreeDictionaryCache; +import com.orange.demo.common.core.base.service.BaseDictService; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import tk.mybatis.mapper.entity.Example; + +import java.util.Collection; +import java.util.List; + +/** + * 行政区划的Service类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Service +public class AreaCodeService extends BaseDictService { + + @Autowired + private AreaCodeMapper areaCodeMapper; + + public AreaCodeService() { + super(); + this.dictionaryCache = MapTreeDictionaryCache.create(AreaCode::getAreaId, AreaCode::getParentId); + } + + @Override + protected BaseDaoMapper mapper() { + return areaCodeMapper; + } + + /** + * 加载数据库数据到内存缓存。 + */ + @Override + public void loadCachedData() { + Example e = new Example(AreaCode.class); + e.orderBy("areaLevel"); + List areaCodeList = areaCodeMapper.selectByExample(e); + dictionaryCache.putAll(areaCodeList); + } + + /** + * 根据上级行政区划Id,获取其下级行政区划列表。 + * + * @param parentId 上级行政区划Id。 + * @return 下级行政区划列表。 + */ + public Collection getListByParentId(Long parentId) { + return ((MapTreeDictionaryCache) dictionaryCache).getListByParentId(parentId); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/CourseService.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/CourseService.java new file mode 100644 index 00000000..56c34984 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/CourseService.java @@ -0,0 +1,175 @@ +package com.orange.demo.app.service; + +import com.orange.demo.app.dao.*; +import com.orange.demo.app.model.*; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.object.TokenData; +import com.orange.demo.common.core.object.MyWhereCriteria; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 课程数据数据操作服务类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Service +public class CourseService extends BaseService { + + @Autowired + private CourseMapper courseMapper; + @Autowired + private ClassCourseMapper classCourseMapper; + @Autowired + private GradeService gradeService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return courseMapper; + } + + /** + * 保存新增对象。 + * + * @param course 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + public Course saveNew(Course course) { + course.setCourseId(idGenerator.nextLongId()); + TokenData tokenData = TokenData.takeFromRequest(); + course.setCreateUserId(tokenData.getUserId()); + Date now = new Date(); + course.setCreateTime(now); + course.setUpdateTime(now); + courseMapper.insert(course); + return course; + } + + /** + * 更新数据对象。 + * + * @param course 更新的对象。 + * @param originalCourse 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(Course course, Course originalCourse) { + course.setCreateUserId(originalCourse.getCreateUserId()); + course.setCreateTime(originalCourse.getCreateTime()); + course.setUpdateTime(new Date()); + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + return courseMapper.updateByPrimaryKey(course) == 1; + } + + /** + * 删除指定数据。 + * + * @param courseId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long courseId) { + // 这里先删除主数据 + if (courseMapper.deleteByPrimaryKey(courseId) == 0) { + return false; + } + // 这里可继续删除关联数据。 + // 开始删除多对多父表的关联 + ClassCourse classCourse = new ClassCourse(); + classCourse.setCourseId(courseId); + classCourseMapper.delete(classCourse); + return true; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getCourseListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getCourseList(Course filter, String orderBy) { + return courseMapper.getCourseList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getCourseList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getCourseListWithRelation(Course filter, String orderBy) { + List resultList = courseMapper.getCourseList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap); + return resultList; + } + + /** + * 在多对多关系中,当前Service的数据表为从表,返回不与指定主表主键Id存在对多对关系的列表。 + * + * @param classId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getNotInCourseListByClassId( + Long classId, Course filter, String orderBy) { + List resultList = + courseMapper.getNotInCourseListByClassId(classId, filter, orderBy); + this.buildRelationForDataList(resultList, MyRelationParam.dictOnly(), null); + return resultList; + } + + /** + * 在多对多关系中,当前Service的数据表为从表,返回与指定主表主键Id存在对多对关系的列表。 + * + * @param classId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getCourseListByClassId( + Long classId, Course filter, String orderBy) { + List resultList = + courseMapper.getCourseListByClassId(classId, filter, orderBy); + this.buildRelationForDataList(resultList, MyRelationParam.dictOnly(), null); + return resultList; + } + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param course 最新数据对象。 + * @param originalCourse 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + public CallResult verifyRelatedData(Course course, Course originalCourse) { + String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!"; + //这里是基于字典的验证。 + if (this.needToVerify(course, originalCourse, Course::getGradeId) + && !gradeService.existId(course.getGradeId())) { + return CallResult.error(String.format(errorMessageFormat, "所属年级")); + } + return CallResult.ok(); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/CourseTransStatsService.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/CourseTransStatsService.java new file mode 100644 index 00000000..77f15cbb --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/CourseTransStatsService.java @@ -0,0 +1,83 @@ +package com.orange.demo.app.service; + +import com.orange.demo.app.dao.*; +import com.orange.demo.app.model.*; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.object.MyWhereCriteria; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.base.service.BaseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 课程统计数据操作服务类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Service +public class CourseTransStatsService extends BaseService { + + @Autowired + private CourseTransStatsMapper courseTransStatsMapper; + @Autowired + private GradeService gradeService; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return courseTransStatsMapper; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getCourseTransStatsListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getCourseTransStatsList(CourseTransStats filter, String orderBy) { + return courseTransStatsMapper.getCourseTransStatsList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getCourseTransStatsList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getCourseTransStatsListWithRelation(CourseTransStats filter, String orderBy) { + List resultList = courseTransStatsMapper.getCourseTransStatsList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap); + return resultList; + } + + /** + * 获取分组过滤后的数据查询结果,以及关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * + * @param filter 过滤对象。 + * @param groupSelect 分组显示列表参数。位于SQL语句SELECT的后面。 + * @param groupBy 分组参数。位于SQL语句的GROUP BY后面。 + * @param orderBy 排序字符串,ORDER BY从句的参数。 + * @return 分组过滤结果集。 + */ + public List getGroupedCourseTransStatsListWithRelation( + CourseTransStats filter, String groupSelect, String groupBy, String orderBy) { + List resultList = + courseTransStatsMapper.getGroupedCourseTransStatsList(filter, groupSelect, groupBy, orderBy); + // NOTE: 这里只是包含了关联数据,聚合计算数据没有包含。 + // 主要原因是,由于聚合字段通常被视为普通字段使用,不会在group by的从句中出现,语义上也不会在此关联。 + this.buildRelationForDataList(resultList, MyRelationParam.normal(), null); + return resultList; + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/GradeService.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/GradeService.java new file mode 100644 index 00000000..518fa2a6 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/GradeService.java @@ -0,0 +1,88 @@ +package com.orange.demo.app.service; + +import com.orange.demo.common.core.base.service.BaseDictService; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.cache.MapDictionaryCache; +import com.orange.demo.common.core.constant.GlobalDeletedFlag; +import com.orange.demo.app.dao.GradeMapper; +import com.orange.demo.app.model.Grade; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * 年级数据操作服务类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Service +public class GradeService extends BaseDictService { + + @Autowired + private GradeMapper gradeMapper; + + public GradeService() { + super(); + this.dictionaryCache = MapDictionaryCache.create(Grade::getGradeId); + } + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return gradeMapper; + } + + /** + * 保存新增对象。 + * + * @param grade 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + public Grade saveNew(Grade grade) { + grade.setStatus(GlobalDeletedFlag.NORMAL); + gradeMapper.insert(grade); + dictionaryCache.put(grade.getGradeId(), grade); + return grade; + } + + /** + * 更新数据对象。 + * + * @param grade 更新的对象。 + * @param originalGrade 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(Grade grade, Grade originalGrade) { + grade.setStatus(GlobalDeletedFlag.NORMAL); + if (gradeMapper.updateByPrimaryKey(grade) != 1) { + return false; + } + dictionaryCache.put(grade.getGradeId(), grade); + return true; + } + + /** + * 删除指定数据。 + * + * @param gradeId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Integer gradeId) { + Grade deletedObject = new Grade(); + deletedObject.setGradeId(gradeId); + deletedObject.setStatus(GlobalDeletedFlag.DELETED); + if (gradeMapper.updateByPrimaryKeySelective(deletedObject) != 1) { + return false; + } + dictionaryCache.invalidate(gradeId); + return true; + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/SchoolInfoService.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/SchoolInfoService.java new file mode 100644 index 00000000..f5cda76c --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/SchoolInfoService.java @@ -0,0 +1,128 @@ +package com.orange.demo.app.service; + +import com.orange.demo.app.dao.*; +import com.orange.demo.app.model.*; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.object.MyWhereCriteria; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 校区数据数据操作服务类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Service +public class SchoolInfoService extends BaseService { + + @Autowired + private SchoolInfoMapper schoolInfoMapper; + @Autowired + private AreaCodeService areaCodeService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return schoolInfoMapper; + } + + /** + * 保存新增对象。 + * + * @param schoolInfo 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + public SchoolInfo saveNew(SchoolInfo schoolInfo) { + schoolInfo.setSchoolId(idGenerator.nextLongId()); + schoolInfoMapper.insert(schoolInfo); + return schoolInfo; + } + + /** + * 更新数据对象。 + * + * @param schoolInfo 更新的对象。 + * @param originalSchoolInfo 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(SchoolInfo schoolInfo, SchoolInfo originalSchoolInfo) { + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + return schoolInfoMapper.updateByPrimaryKey(schoolInfo) == 1; + } + + /** + * 删除指定数据。 + * + * @param schoolId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long schoolId) { + return schoolInfoMapper.deleteByPrimaryKey(schoolId) != 0; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getSchoolInfoListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getSchoolInfoList(SchoolInfo filter, String orderBy) { + return schoolInfoMapper.getSchoolInfoList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getSchoolInfoList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getSchoolInfoListWithRelation(SchoolInfo filter, String orderBy) { + List resultList = schoolInfoMapper.getSchoolInfoList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap); + return resultList; + } + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param schoolInfo 最新数据对象。 + * @param originalSchoolInfo 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + public CallResult verifyRelatedData(SchoolInfo schoolInfo, SchoolInfo originalSchoolInfo) { + String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!"; + //这里是基于字典的验证。 + if (this.needToVerify(schoolInfo, originalSchoolInfo, SchoolInfo::getProvinceId) + && !areaCodeService.existId(schoolInfo.getProvinceId())) { + return CallResult.error(String.format(errorMessageFormat, "所在省份")); + } + //这里是基于字典的验证。 + if (this.needToVerify(schoolInfo, originalSchoolInfo, SchoolInfo::getCityId) + && !areaCodeService.existId(schoolInfo.getCityId())) { + return CallResult.error(String.format(errorMessageFormat, "所在城市")); + } + return CallResult.ok(); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/StudentActionStatsService.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/StudentActionStatsService.java new file mode 100644 index 00000000..15953a34 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/StudentActionStatsService.java @@ -0,0 +1,85 @@ +package com.orange.demo.app.service; + +import com.orange.demo.app.dao.*; +import com.orange.demo.app.model.*; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.object.MyWhereCriteria; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.base.service.BaseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 学生行为统计数据操作服务类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Service +public class StudentActionStatsService extends BaseService { + + @Autowired + private StudentActionStatsMapper studentActionStatsMapper; + @Autowired + private GradeService gradeService; + @Autowired + private AreaCodeService areaCodeService; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return studentActionStatsMapper; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getStudentActionStatsListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentActionStatsList(StudentActionStats filter, String orderBy) { + return studentActionStatsMapper.getStudentActionStatsList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getStudentActionStatsList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentActionStatsListWithRelation(StudentActionStats filter, String orderBy) { + List resultList = studentActionStatsMapper.getStudentActionStatsList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap); + return resultList; + } + + /** + * 获取分组过滤后的数据查询结果,以及关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * + * @param filter 过滤对象。 + * @param groupSelect 分组显示列表参数。位于SQL语句SELECT的后面。 + * @param groupBy 分组参数。位于SQL语句的GROUP BY后面。 + * @param orderBy 排序字符串,ORDER BY从句的参数。 + * @return 分组过滤结果集。 + */ + public List getGroupedStudentActionStatsListWithRelation( + StudentActionStats filter, String groupSelect, String groupBy, String orderBy) { + List resultList = + studentActionStatsMapper.getGroupedStudentActionStatsList(filter, groupSelect, groupBy, orderBy); + // NOTE: 这里只是包含了关联数据,聚合计算数据没有包含。 + // 主要原因是,由于聚合字段通常被视为普通字段使用,不会在group by的从句中出现,语义上也不会在此关联。 + this.buildRelationForDataList(resultList, MyRelationParam.normal(), null); + return resultList; + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/StudentActionTransService.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/StudentActionTransService.java new file mode 100644 index 00000000..085e135f --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/StudentActionTransService.java @@ -0,0 +1,130 @@ +package com.orange.demo.app.service; + +import com.orange.demo.app.dao.*; +import com.orange.demo.app.model.*; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.object.MyWhereCriteria; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 学生行为流水数据操作服务类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Service +public class StudentActionTransService extends BaseService { + + @Autowired + private StudentActionTransMapper studentActionTransMapper; + @Autowired + private SchoolInfoService schoolInfoService; + @Autowired + private GradeService gradeService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return studentActionTransMapper; + } + + /** + * 保存新增对象。 + * + * @param studentActionTrans 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + public StudentActionTrans saveNew(StudentActionTrans studentActionTrans) { + studentActionTrans.setTransId(idGenerator.nextLongId()); + studentActionTransMapper.insert(studentActionTrans); + return studentActionTrans; + } + + /** + * 更新数据对象。 + * + * @param studentActionTrans 更新的对象。 + * @param originalStudentActionTrans 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(StudentActionTrans studentActionTrans, StudentActionTrans originalStudentActionTrans) { + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + return studentActionTransMapper.updateByPrimaryKey(studentActionTrans) == 1; + } + + /** + * 删除指定数据。 + * + * @param transId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long transId) { + return studentActionTransMapper.deleteByPrimaryKey(transId) != 0; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getStudentActionTransListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentActionTransList(StudentActionTrans filter, String orderBy) { + return studentActionTransMapper.getStudentActionTransList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getStudentActionTransList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentActionTransListWithRelation(StudentActionTrans filter, String orderBy) { + List resultList = studentActionTransMapper.getStudentActionTransList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap); + return resultList; + } + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param studentActionTrans 最新数据对象。 + * @param originalStudentActionTrans 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + public CallResult verifyRelatedData(StudentActionTrans studentActionTrans, StudentActionTrans originalStudentActionTrans) { + String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!"; + //这里是基于字典的验证。 + if (this.needToVerify(studentActionTrans, originalStudentActionTrans, StudentActionTrans::getSchoolId) + && !schoolInfoService.existId(studentActionTrans.getSchoolId())) { + return CallResult.error(String.format(errorMessageFormat, "学生校区")); + } + //这里是基于字典的验证。 + if (this.needToVerify(studentActionTrans, originalStudentActionTrans, StudentActionTrans::getGradeId) + && !gradeService.existId(studentActionTrans.getGradeId())) { + return CallResult.error(String.format(errorMessageFormat, "学生年级")); + } + return CallResult.ok(); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/StudentClassService.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/StudentClassService.java new file mode 100644 index 00000000..086c437a --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/StudentClassService.java @@ -0,0 +1,255 @@ +package com.orange.demo.app.service; + +import com.orange.demo.app.dao.*; +import com.orange.demo.app.model.*; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.constant.GlobalDeletedFlag; +import com.orange.demo.common.core.object.TokenData; +import com.orange.demo.common.core.object.MyWhereCriteria; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import tk.mybatis.mapper.entity.Example; + +import java.util.*; + +/** + * 班级数据数据操作服务类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Service +public class StudentClassService extends BaseService { + + @Autowired + private StudentClassMapper studentClassMapper; + @Autowired + private ClassCourseMapper classCourseMapper; + @Autowired + private ClassStudentMapper classStudentMapper; + @Autowired + private SchoolInfoService schoolInfoService; + @Autowired + private StudentService studentService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return studentClassMapper; + } + + /** + * 保存新增对象。 + * + * @param studentClass 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + public StudentClass saveNew(StudentClass studentClass) { + studentClass.setClassId(idGenerator.nextLongId()); + TokenData tokenData = TokenData.takeFromRequest(); + studentClass.setCreateUserId(tokenData.getUserId()); + studentClass.setCreateTime(new Date()); + studentClass.setStatus(GlobalDeletedFlag.NORMAL); + if (studentClass.getFinishClassHour() == null) { + studentClass.setFinishClassHour(0); + } + studentClassMapper.insert(studentClass); + return studentClass; + } + + /** + * 更新数据对象。 + * + * @param studentClass 更新的对象。 + * @param originalStudentClass 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(StudentClass studentClass, StudentClass originalStudentClass) { + studentClass.setCreateUserId(originalStudentClass.getCreateUserId()); + studentClass.setCreateTime(originalStudentClass.getCreateTime()); + studentClass.setStatus(GlobalDeletedFlag.NORMAL); + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + return studentClassMapper.updateByPrimaryKey(studentClass) == 1; + } + + /** + * 删除指定数据。 + * + * @param classId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long classId) { + Example studentClassExample = new Example(StudentClass.class); + Example.Criteria c = studentClassExample.createCriteria(); + c.andEqualTo(super.idFieldName, classId); + c.andEqualTo(super.deletedFlagFieldName, GlobalDeletedFlag.NORMAL); + // 这里先删除主数据 + StudentClass deletedObject = new StudentClass(); + deletedObject.setStatus(GlobalDeletedFlag.DELETED); + if (studentClassMapper.updateByExampleSelective(deletedObject, studentClassExample) == 0) { + return false; + } + // 开始删除多对多子表的关联 + ClassCourse classCourse = new ClassCourse(); + classCourse.setClassId(classId); + classCourseMapper.delete(classCourse); + ClassStudent classStudent = new ClassStudent(); + classStudent.setClassId(classId); + classStudentMapper.delete(classStudent); + return true; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getStudentClassListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentClassList(StudentClass filter, String orderBy) { + return studentClassMapper.getStudentClassList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getStudentClassList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentClassListWithRelation(StudentClass filter, String orderBy) { + List resultList = studentClassMapper.getStudentClassList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap); + return resultList; + } + + /** + * 批量添加多对多关联关系。 + * + * @param classCourseList 多对多关联表对象集合。 + * @param classId 主表Id。 + */ + @Transactional(rollbackFor = Exception.class) + public void addClassCourseList(List classCourseList, Long classId) { + for (ClassCourse classCourse : classCourseList) { + classCourse.setClassId(classId); + if (classCourse.getCourseOrder() == null) { + classCourse.setCourseOrder(0); + } + } + classCourseMapper.insertList(classCourseList); + } + + /** + * 更新中间表数据。 + * + * @param classCourse 中间表对象。 + * @return 更新成功与否。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean updateClassCourse(ClassCourse classCourse) { + Example e = new Example(ClassCourse.class); + e.createCriteria() + .andEqualTo("classId", classCourse.getClassId()) + .andEqualTo("courseId", classCourse.getCourseId()); + return classCourseMapper.updateByExample(classCourse, e) > 0; + } + + /** + * 获取中间表数据。 + * + * @param classId 主表Id。 + * @param courseId 从表Id。 + * @return 中间表对象。 + */ + public ClassCourse getClassCourse(Long classId, Long courseId) { + Example e = new Example(ClassCourse.class); + e.createCriteria() + .andEqualTo("classId", classId) + .andEqualTo("courseId", courseId); + return classCourseMapper.selectOneByExample(e); + } + + /** + * 移除单条多对多关系。 + * + * @param classId 主表Id。 + * @param courseId 从表Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean removeClassCourse(Long classId, Long courseId) { + ClassCourse classCourse = new ClassCourse(); + classCourse.setClassId(classId); + classCourse.setCourseId(courseId); + return classCourseMapper.delete(classCourse) > 0; + } + + /** + * 批量添加多对多关联关系。 + * + * @param classStudentList 多对多关联表对象集合。 + * @param classId 主表Id。 + */ + @Transactional(rollbackFor = Exception.class) + public void addClassStudentList(List classStudentList, Long classId) { + for (ClassStudent classStudent : classStudentList) { + classStudent.setClassId(classId); + } + classStudentMapper.insertList(classStudentList); + } + + /** + * 移除单条多对多关系。 + * + * @param classId 主表Id。 + * @param studentId 从表Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean removeClassStudent(Long classId, Long studentId) { + ClassStudent classStudent = new ClassStudent(); + classStudent.setClassId(classId); + classStudent.setStudentId(studentId); + return classStudentMapper.delete(classStudent) > 0; + } + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param studentClass 最新数据对象。 + * @param originalStudentClass 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + public CallResult verifyRelatedData(StudentClass studentClass, StudentClass originalStudentClass) { + String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!"; + //这里是基于字典的验证。 + if (this.needToVerify(studentClass, originalStudentClass, StudentClass::getSchoolId) + && !schoolInfoService.existId(studentClass.getSchoolId())) { + return CallResult.error(String.format(errorMessageFormat, "所属校区")); + } + //这里是基于字典的验证。 + if (this.needToVerify(studentClass, originalStudentClass, StudentClass::getLeaderId) + && !studentService.existId(studentClass.getLeaderId())) { + return CallResult.error(String.format(errorMessageFormat, "学生班长")); + } + return CallResult.ok(); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/StudentService.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/StudentService.java new file mode 100644 index 00000000..31fd3ec2 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/app/service/StudentService.java @@ -0,0 +1,202 @@ +package com.orange.demo.app.service; + +import com.orange.demo.application.common.constant.StudentStatus; +import com.orange.demo.app.dao.*; +import com.orange.demo.app.model.*; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.object.MyWhereCriteria; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 学生数据数据操作服务类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Service +public class StudentService extends BaseService { + + @Autowired + private StudentMapper studentMapper; + @Autowired + private ClassStudentMapper classStudentMapper; + @Autowired + private AreaCodeService areaCodeService; + @Autowired + private GradeService gradeService; + @Autowired + private SchoolInfoService schoolInfoService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return studentMapper; + } + + /** + * 保存新增对象。 + * + * @param student 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + public Student saveNew(Student student) { + student.setStudentId(idGenerator.nextLongId()); + student.setRegisterTime(new Date()); + if (student.getTotalCoin() == null) { + student.setTotalCoin(0); + } + if (student.getLeftCoin() == null) { + student.setLeftCoin(0); + } + if (student.getStatus() == null) { + student.setStatus(StudentStatus.NORMAL); + } + studentMapper.insert(student); + return student; + } + + /** + * 更新数据对象。 + * + * @param student 更新的对象。 + * @param originalStudent 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(Student student, Student originalStudent) { + student.setRegisterTime(originalStudent.getRegisterTime()); + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + return studentMapper.updateByPrimaryKey(student) == 1; + } + + /** + * 删除指定数据。 + * + * @param studentId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long studentId) { + // 这里先删除主数据 + if (studentMapper.deleteByPrimaryKey(studentId) == 0) { + return false; + } + // 这里可继续删除关联数据。 + // 开始删除多对多父表的关联 + ClassStudent classStudent = new ClassStudent(); + classStudent.setStudentId(studentId); + classStudentMapper.delete(classStudent); + return true; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getStudentListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentList(Student filter, String orderBy) { + return studentMapper.getStudentList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getStudentList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentListWithRelation(Student filter, String orderBy) { + List resultList = studentMapper.getStudentList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap); + return resultList; + } + + /** + * 在多对多关系中,当前Service的数据表为从表,返回不与指定主表主键Id存在对多对关系的列表。 + * + * @param classId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getNotInStudentListByClassId( + Long classId, Student filter, String orderBy) { + List resultList = + studentMapper.getNotInStudentListByClassId(classId, filter, orderBy); + this.buildRelationForDataList(resultList, MyRelationParam.dictOnly(), null); + return resultList; + } + + /** + * 在多对多关系中,当前Service的数据表为从表,返回与指定主表主键Id存在对多对关系的列表。 + * + * @param classId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentListByClassId( + Long classId, Student filter, String orderBy) { + List resultList = + studentMapper.getStudentListByClassId(classId, filter, orderBy); + this.buildRelationForDataList(resultList, MyRelationParam.dictOnly(), null); + return resultList; + } + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param student 最新数据对象。 + * @param originalStudent 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + public CallResult verifyRelatedData(Student student, Student originalStudent) { + String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!"; + //这里是基于字典的验证。 + if (this.needToVerify(student, originalStudent, Student::getProvinceId) + && !areaCodeService.existId(student.getProvinceId())) { + return CallResult.error(String.format(errorMessageFormat, "所在省份")); + } + //这里是基于字典的验证。 + if (this.needToVerify(student, originalStudent, Student::getCityId) + && !areaCodeService.existId(student.getCityId())) { + return CallResult.error(String.format(errorMessageFormat, "所在城市")); + } + //这里是基于字典的验证。 + if (this.needToVerify(student, originalStudent, Student::getDistrictId) + && !areaCodeService.existId(student.getDistrictId())) { + return CallResult.error(String.format(errorMessageFormat, "所在区县")); + } + //这里是基于字典的验证。 + if (this.needToVerify(student, originalStudent, Student::getGradeId) + && !gradeService.existId(student.getGradeId())) { + return CallResult.error(String.format(errorMessageFormat, "年级")); + } + //这里是基于字典的验证。 + if (this.needToVerify(student, originalStudent, Student::getSchoolId) + && !schoolInfoService.existId(student.getSchoolId())) { + return CallResult.error(String.format(errorMessageFormat, "所属校区")); + } + return CallResult.ok(); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/config/ApplicationConfig.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/config/ApplicationConfig.java new file mode 100644 index 00000000..95711baa --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/config/ApplicationConfig.java @@ -0,0 +1,46 @@ +package com.orange.demo.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * 应用程序自定义的程序属性配置文件。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "application") +public class ApplicationConfig { + + /** + * token的Http Request Header的key + */ + private String tokenHeaderKey; + /** + * token在过期之前,但是已经需要被刷新时,response返回的header信息的key。 + */ + private String refreshedTokenHeaderKey; + /** + * token 加密用的密钥,该值的长度最少10个字符(过短会报错)。 + */ + private String tokenSigningKey; + /** + * 令牌的过期时间,单位毫秒 + */ + private Long expiration; + /** + * 用户密码被重置之后的缺省密码 + */ + private String defaultUserPassword; + /** + * 上传文件的基础目录 + */ + private String uploadFileBaseDir; + /** + * 授信ip列表,没有填写表示全部信任。多个ip之间逗号分隔,如: http://10.10.10.1:8080,http://10.10.10.2:8080 + */ + private String credentialIpList; +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/config/DataSourceConfig.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/config/DataSourceConfig.java new file mode 100644 index 00000000..6131745b --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/config/DataSourceConfig.java @@ -0,0 +1,30 @@ +package com.orange.demo.config; + +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import tk.mybatis.spring.annotation.MapperScan; + +import javax.sql.DataSource; + +/** + * 数据源配置Bean对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Configuration +@EnableTransactionManagement +@MapperScan(value = {"com.orange.demo.*.dao"}) +public class DataSourceConfig { + + @Bean(initMethod = "init", destroyMethod = "close") + @Primary + @ConfigurationProperties(prefix = "spring.datasource.druid") + public DataSource druidDataSource() { + return DruidDataSourceBuilder.create().build(); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/config/FilterConfig.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/config/FilterConfig.java new file mode 100644 index 00000000..bc4e4eb1 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/config/FilterConfig.java @@ -0,0 +1,57 @@ +package com.orange.demo.config; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import javax.servlet.Filter; +import java.nio.charset.StandardCharsets; + +/** + * 这里主要配置Web的各种过滤器和监听器等Servlet容器组件。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Configuration +public class FilterConfig { + + /** + * 配置Ajax跨域过滤器。 + */ + @Bean + public CorsFilter corsFilterRegistration(ApplicationConfig applicationConfig) { + UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource(); + CorsConfiguration corsConfiguration = new CorsConfiguration(); + if (StringUtils.isNotBlank(applicationConfig.getCredentialIpList())) { + String[] credentialIpList = StringUtils.split(applicationConfig.getCredentialIpList(), ","); + if (credentialIpList.length > 0) { + for (String ip : credentialIpList) { + corsConfiguration.addAllowedOrigin(ip); + } + } + corsConfiguration.addAllowedHeader("*"); + corsConfiguration.addAllowedMethod("*"); + corsConfiguration.addExposedHeader(applicationConfig.getRefreshedTokenHeaderKey()); + corsConfiguration.setAllowCredentials(true); + configSource.registerCorsConfiguration("/**", corsConfiguration); + } + return new CorsFilter(configSource); + } + + @Bean + public FilterRegistrationBean characterEncodingFilterRegistration() { + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>( + new org.springframework.web.filter.CharacterEncodingFilter()); + filterRegistrationBean.addUrlPatterns("/*"); + filterRegistrationBean.addInitParameter("encoding", StandardCharsets.UTF_8.name()); + // forceEncoding强制response也被编码,另外即使request中已经设置encoding,forceEncoding也会重新设置 + filterRegistrationBean.addInitParameter("forceEncoding", "true"); + filterRegistrationBean.setAsyncSupported(true); + return filterRegistrationBean; + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/config/InterceptorConfig.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/config/InterceptorConfig.java new file mode 100644 index 00000000..32dd426b --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/config/InterceptorConfig.java @@ -0,0 +1,21 @@ +package com.orange.demo.config; + +import com.orange.demo.interceptor.AuthenticationInterceptor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * 所有的项目拦截器都在这里集中配置 + * + * @author Jerry + * @date 2020-09-24 + */ +@Configuration +public class InterceptorConfig implements WebMvcConfigurer { + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new AuthenticationInterceptor()).addPathPatterns("/admin/**"); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/interceptor/AuthenticationInterceptor.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/interceptor/AuthenticationInterceptor.java new file mode 100644 index 00000000..83139313 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/interceptor/AuthenticationInterceptor.java @@ -0,0 +1,103 @@ +package com.orange.demo.interceptor; + +import com.alibaba.fastjson.JSON; +import com.orange.demo.config.ApplicationConfig; +import com.orange.demo.common.core.annotation.NoAuthInterface; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.object.ResponseResult; +import com.orange.demo.common.core.object.TokenData; +import com.orange.demo.common.core.util.ApplicationContextHolder; +import com.orange.demo.common.core.util.JwtUtil; +import com.orange.demo.common.core.cache.SessionCacheHelper; +import io.jsonwebtoken.Claims; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +/** + * 登录用户Token验证、生成和权限验证的拦截器。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Slf4j +public class AuthenticationInterceptor implements HandlerInterceptor { + + private ApplicationConfig appConfig = + ApplicationContextHolder.getBean("applicationConfig"); + + private SessionCacheHelper cacheHelper = + ApplicationContextHolder.getBean("sessionCacheHelper"); + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + String url = request.getRequestURI(); + // 如果接口方法标记NoAuthInterface注解,可以直接跳过Token鉴权验证,这里主要为了测试接口方便 + if (handler instanceof HandlerMethod) { + HandlerMethod hm = (HandlerMethod) handler; + if (hm.getBeanType().getAnnotation(NoAuthInterface.class) != null + || hm.getMethodAnnotation(NoAuthInterface.class) != null) { + return true; + } + } + String token = request.getHeader(appConfig.getTokenHeaderKey()); + if (StringUtils.isBlank(token)) { + token = request.getParameter(appConfig.getTokenHeaderKey()); + } + Claims c = JwtUtil.parseToken(token, appConfig.getTokenSigningKey()); + if (JwtUtil.isNullOrExpired(c)) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + this.outputResponseMessage(response, + ResponseResult.error(ErrorCodeEnum.UNAUTHORIZED_LOGIN, "用户会话已过期或尚未登录,请重新登录!")); + return false; + } + String sessionId = (String) c.get("sessionId"); + TokenData tokenData = cacheHelper.getTokenData(sessionId); + if (tokenData == null) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + this.outputResponseMessage(response, + ResponseResult.error(ErrorCodeEnum.UNAUTHORIZED_LOGIN, "用户会话已失效,请重新登录!")); + return false; + } + TokenData.addToRequest(tokenData); + if (JwtUtil.needToRefresh(c)) { + String refreshedToken = JwtUtil.generateToken(c, appConfig.getExpiration(), appConfig.getTokenSigningKey()); + response.addHeader(appConfig.getRefreshedTokenHeaderKey(), refreshedToken); + } + return true; + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, + ModelAndView modelAndView) throws Exception { + // 这里需要空注解,否则sonar会不happy。 + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) + throws Exception { + // 这里需要空注解,否则sonar会不happy。 + } + + private void outputResponseMessage(HttpServletResponse response, ResponseResult respObj) { + PrintWriter out; + try { + out = response.getWriter(); + } catch (IOException e) { + log.error("Failed to call OutputResponseMessage.", e); + return; + } + response.setContentType("application/json; charset=utf-8"); + out.print(JSON.toJSONString(respObj)); + out.flush(); + out.close(); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/controller/LoginController.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/controller/LoginController.java new file mode 100644 index 00000000..de6e7206 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/controller/LoginController.java @@ -0,0 +1,142 @@ +package com.orange.demo.upms.controller; + +import com.alibaba.fastjson.JSONObject; +import com.github.xiaoymin.knife4j.annotations.ApiSupport; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import lombok.extern.slf4j.Slf4j; +import com.orange.demo.config.ApplicationConfig; +import com.orange.demo.upms.service.*; +import com.orange.demo.upms.model.SysUser; +import com.orange.demo.upms.model.constant.SysUserStatus; +import com.orange.demo.upms.model.constant.SysUserType; +import com.orange.demo.common.core.annotation.NoAuthInterface; +import com.orange.demo.common.core.constant.ApplicationConstant; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.object.ResponseResult; +import com.orange.demo.common.core.object.TokenData; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.cache.SessionCacheHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.web.bind.annotation.*; + +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.*; + +/** + * 登录接口控制器类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@ApiSupport(order = 1) +@Api(tags = "用户登录接口") +@Slf4j +@RestController +@RequestMapping("/admin/upms/login") +public class LoginController { + + @Autowired + private SysUserService sysUserService; + @Autowired + private ApplicationConfig appConfig; + @Autowired + private SessionCacheHelper cacheHelper; + @Autowired + private PasswordEncoder passwordEncoder; + + /** + * 登录接口。 + * + * @param loginName 登录名。 + * @param password 密码。 + * @return 应答结果对象,其中包括JWT的Token数据,以及菜单列表。 + */ + @ApiImplicitParams({ + // 这里包含密码密文,仅用于方便开发期间的接口测试,集成测试和发布阶段,需要将当前注解去掉。 + // 如果您重新生成了公钥和私钥,请替换password的缺省值。 + @ApiImplicitParam(name = "loginName", defaultValue = "admin"), + @ApiImplicitParam(name = "password", defaultValue = "IP3ccke3GhH45iGHB5qP9p7iZw6xUyj28Ju10rnBiPKOI35sc%2BjI7%2FdsjOkHWMfUwGYGfz8ik31HC2Ruk%2Fhkd9f6RPULTHj7VpFdNdde2P9M4mQQnFBAiPM7VT9iW3RyCtPlJexQ3nAiA09OqG%2F0sIf1kcyveSrulxembARDbDo%3D") + }) + @NoAuthInterface + @GetMapping("/doLogin") + public ResponseResult doLogin( + @RequestParam String loginName, @RequestParam String password) throws Exception { + if (MyCommonUtil.existBlankArgument(loginName, password)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SysUser user = sysUserService.getSysUserByLoginName(loginName); + password = URLDecoder.decode(password, StandardCharsets.UTF_8.name()); + //NOTE: 第一次使用时,请务必阅读ApplicationConstant.PRIVATE_KEY的代码注释。 + //执行RsaUtil工具类中的main函数,可以生成新的公钥和私钥。 + password = RsaUtil.decrypt(password, ApplicationConstant.PRIVATE_KEY); + if (user == null || !passwordEncoder.matches(password, user.getPassword())) { + return ResponseResult.error(ErrorCodeEnum.INVALID_USERNAME_PASSWORD); + } + String errorMessage; + if (user.getUserStatus() == SysUserStatus.STATUS_LOCKED) { + errorMessage = "登录失败,用户账号被锁定!"; + return ResponseResult.error(ErrorCodeEnum.INVALID_USER_STATUS, errorMessage); + } + boolean isAdmin = user.getUserType() == SysUserType.TYPE_ADMIN; + Map claims = new HashMap<>(3); + String sessionId = MyCommonUtil.generateUuid(); + claims.put("sessionId", sessionId); + String token = JwtUtil.generateToken(claims, appConfig.getExpiration(), appConfig.getTokenSigningKey()); + JSONObject jsonData = new JSONObject(); + jsonData.put(TokenData.REQUEST_ATTRIBUTE_NAME, token); + jsonData.put("showName", user.getShowName()); + jsonData.put("isAdmin", isAdmin); + TokenData tokenData = new TokenData(); + tokenData.setSessionId(sessionId); + tokenData.setUserId(user.getUserId()); + tokenData.setShowName(user.getShowName()); + tokenData.setIsAdmin(isAdmin); + cacheHelper.putTokenData(sessionId, tokenData); + return ResponseResult.success(jsonData); + } + + /** + * 登出操作。同时将Session相关的信息从缓存中删除。 + * + * @return 应答结果对象。 + */ + @PostMapping("/doLogout") + public ResponseResult doLogout() { + cacheHelper.removeAllSessionCache(); + return ResponseResult.success(); + } + + /** + * 用户修改自己的密码。 + * + * @param oldPass 原有密码。 + * @param newPass 新密码。 + * @return 应答结果对象。 + */ + @PostMapping("/changePassword") + public ResponseResult changePassword( + @RequestParam String oldPass, @RequestParam String newPass) throws Exception { + if (MyCommonUtil.existBlankArgument(oldPass, oldPass)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + TokenData tokenData = TokenData.takeFromRequest(); + SysUser user = sysUserService.getById(tokenData.getUserId()); + oldPass = URLDecoder.decode(oldPass, StandardCharsets.UTF_8.name()); + //NOTE: 第一次使用时,请务必阅读ApplicationConstant.PRIVATE_KEY的代码注释。 + //执行RsaUtil工具类中的main函数,可以生成新的公钥和私钥。 + oldPass = RsaUtil.decrypt(oldPass, ApplicationConstant.PRIVATE_KEY); + if (user == null || !passwordEncoder.matches(oldPass, user.getPassword())) { + return ResponseResult.error(ErrorCodeEnum.INVALID_USERNAME_PASSWORD); + } + newPass = URLDecoder.decode(newPass, StandardCharsets.UTF_8.name()); + newPass = RsaUtil.decrypt(newPass, ApplicationConstant.PRIVATE_KEY); + if (!sysUserService.changePassword(tokenData.getUserId(), newPass)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/controller/SysUserController.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/controller/SysUserController.java new file mode 100644 index 00000000..5e0dadf2 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/controller/SysUserController.java @@ -0,0 +1,177 @@ +package com.orange.demo.upms.controller; + +import com.github.pagehelper.page.PageMethod; +import com.orange.demo.upms.model.*; +import com.orange.demo.upms.service.*; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.constant.*; +import com.orange.demo.common.core.annotation.MyRequestBody; +import com.orange.demo.common.core.validator.AddGroup; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.config.ApplicationConfig; +import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; +import io.swagger.annotations.Api; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import javax.validation.groups.Default; + +/** + * 用户管理操作控制器类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Api(tags = "用户管理管理接口") +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysUser") +public class SysUserController { + + @Autowired + private SysUserService sysUserService; + @Autowired + private PasswordEncoder passwordEncoder; + @Autowired + private ApplicationConfig appConfig; + + /** + * 新增用户操作。 + * + * @param sysUser 新增用户对象。 + * @return 应答结果对象,包含新增用户的主键Id。 + */ + @ApiOperationSupport(ignoreParameters = { + "sysUser.userId", + "sysUser.createTimeStart", + "sysUser.createTimeEnd"}) + @PostMapping("/add") + public ResponseResult add(@MyRequestBody SysUser sysUser) { + String errorMessage = MyCommonUtil.getModelValidationError(sysUser, Default.class, AddGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + CallResult result = sysUserService.verifyRelatedData(sysUser, null); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage()); + } + sysUserService.saveNew(sysUser); + return ResponseResult.success(sysUser.getUserId()); + } + + /** + * 更新用户操作。 + * + * @param sysUser 更新用户对象。 + * @return 应答结果对象。 + */ + @ApiOperationSupport(ignoreParameters = { + "sysUser.createTimeStart", + "sysUser.createTimeEnd"}) + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysUser sysUser) { + String errorMessage = MyCommonUtil.getModelValidationError(sysUser, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + SysUser originalUser = sysUserService.getById(sysUser.getUserId()); + if (originalUser == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + CallResult result = sysUserService.verifyRelatedData(sysUser, originalUser); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage()); + } + if (!sysUserService.update(sysUser, originalUser)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 重置密码操作。 + * + * @param userId 指定用户主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/resetPassword") + public ResponseResult resetPassword(@MyRequestBody Long userId) { + if (MyCommonUtil.existBlankArgument(userId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!sysUserService.changePassword(userId, appConfig.getDefaultUserPassword())) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除用户管理数据。 + * + * @param userId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long userId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(userId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + SysUser originalSysUser = sysUserService.getById(userId); + if (originalSysUser == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!sysUserService.remove(userId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的用户管理列表。 + * + * @param sysUserFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody SysUser sysUserFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class); + List resultList = sysUserService.getSysUserListWithRelation(sysUserFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定用户管理对象详情。 + * + * @param userId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long userId) { + if (MyCommonUtil.existBlankArgument(userId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 这里查看用户数据时候,需要把用户多对多关联的角色和数据权限Id一并查出。 + SysUser sysUser = sysUserService.getByIdWithRelation(userId, MyRelationParam.full()); + if (sysUser == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(sysUser); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/dao/SysUserMapper.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/dao/SysUserMapper.java new file mode 100644 index 00000000..c6057ffe --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/dao/SysUserMapper.java @@ -0,0 +1,26 @@ +package com.orange.demo.upms.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.upms.model.SysUser; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 用户管理数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-24 + */ +public interface SysUserMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param sysUserFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getSysUserList( + @Param("sysUserFilter") SysUser sysUserFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/dao/mapper/SysUserMapper.xml b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/dao/mapper/SysUserMapper.xml new file mode 100644 index 00000000..0f6e7330 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/dao/mapper/SysUserMapper.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + AND zz_sys_user.login_name LIKE #{safeLoginName} + + + + AND zz_sys_user.show_name LIKE #{safeShowName} + + + AND zz_sys_user.user_status = #{sysUserFilter.userStatus} + + + AND zz_sys_user.create_time >= #{sysUserFilter.createTimeStart} + + + AND zz_sys_user.create_time <= #{sysUserFilter.createTimeEnd} + + + AND zz_sys_user.deleted_flag = ${@com.orange.demo.common.core.constant.GlobalDeletedFlag@NORMAL} + + + + SELECT * FROM zz_sys_user + + + + + ORDER BY ${orderBy} + + + diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/model/SysUser.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/model/SysUser.java new file mode 100644 index 00000000..b6a1da57 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/model/SysUser.java @@ -0,0 +1,152 @@ +package com.orange.demo.upms.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.demo.upms.model.constant.SysUserType; +import com.orange.demo.upms.model.constant.SysUserStatus; +import com.orange.demo.common.core.annotation.RelationConstDict; +import com.orange.demo.common.core.annotation.DeletedFlagColumn; +import com.orange.demo.common.core.validator.AddGroup; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.validator.ConstDictRef; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Date; +import java.util.Map; + +/** + * SysUser实体对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +@ApiModel("SysUser实体对象") +@Data +@Table(name = "zz_sys_user") +public class SysUser { + + /** + * 用户Id。 + */ + @ApiModelProperty(value = "用户Id", required = true) + @NotNull(message = "数据验证失败,用户Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "user_id") + private Long userId; + + /** + * 登录用户名。 + */ + @ApiModelProperty(value = "登录用户名", required = true) + @NotBlank(message = "数据验证失败,登录用户名不能为空!") + @Column(name = "login_name") + private String loginName; + + /** + * 用户密码。 + */ + @ApiModelProperty(value = "用户密码", required = true) + @NotBlank(message = "数据验证失败,用户密码不能为空!", groups = {AddGroup.class}) + private String password; + + /** + * 用户显示名称。 + */ + @ApiModelProperty(value = "用户显示名称", required = true) + @NotBlank(message = "数据验证失败,用户显示名称不能为空!") + @Column(name = "show_name") + private String showName; + + /** + * 用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)。 + */ + @ApiModelProperty(value = "用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)", required = true) + @NotNull(message = "数据验证失败,用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)不能为空!") + @ConstDictRef(constDictClass = SysUserType.class, message = "数据验证失败,用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)为无效值!") + @Column(name = "user_type") + private Integer userType; + + /** + * 用户头像的Url。 + */ + @ApiModelProperty(value = "用户头像的Url") + @Column(name = "head_image_url") + private String headImageUrl; + + /** + * 用户状态(0: 正常 1: 锁定)。 + */ + @ApiModelProperty(value = "用户状态(0: 正常 1: 锁定)", required = true) + @NotNull(message = "数据验证失败,用户状态(0: 正常 1: 锁定)不能为空!") + @ConstDictRef(constDictClass = SysUserStatus.class, message = "数据验证失败,用户状态(0: 正常 1: 锁定)为无效值!") + @Column(name = "user_status") + private Integer userStatus; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @ApiModelProperty(hidden = true) + @JSONField(serialize = false) + @DeletedFlagColumn + @Column(name = "deleted_flag") + private Integer deletedFlag; + + /** + * 创建用户Id。 + */ + @ApiModelProperty(value = "创建用户Id") + @Column(name = "create_user_id") + private Long createUserId; + + /** + * 创建用户名。 + */ + @ApiModelProperty(value = "创建用户名") + @Column(name = "create_username") + private String createUsername; + + /** + * 创建时间。 + */ + @ApiModelProperty(value = "创建时间") + @Column(name = "create_time") + private Date createTime; + + /** + * 更新时间。 + */ + @ApiModelProperty(value = "更新时间") + @Column(name = "update_time") + private Date updateTime; + + /** + * createTime 范围过滤起始值(>=)。 + */ + @ApiModelProperty(value = "createTime 范围过滤起始值(>=)") + @Transient + private String createTimeStart; + + /** + * createTime 范围过滤结束值(<=)。 + */ + @ApiModelProperty(value = "createTime 范围过滤结束值(<=)") + @Transient + private String createTimeEnd; + + @ApiModelProperty(hidden = true) + @RelationConstDict( + masterIdField = "userType", + constantDictClass = SysUserType.class) + @Transient + private Map userTypeDictMap; + + @ApiModelProperty(hidden = true) + @RelationConstDict( + masterIdField = "userStatus", + constantDictClass = SysUserStatus.class) + @Transient + private Map userStatusDictMap; +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/model/constant/SysUserStatus.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/model/constant/SysUserStatus.java new file mode 100644 index 00000000..501f1beb --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/model/constant/SysUserStatus.java @@ -0,0 +1,44 @@ +package com.orange.demo.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 用户状态常量字典对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +public final class SysUserStatus { + + /** + * 正常状态。 + */ + public static final int STATUS_NORMAL = 0; + /** + * 锁定状态。 + */ + public static final int STATUS_LOCKED = 1; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(STATUS_NORMAL, "正常状态"); + DICT_MAP.put(STATUS_LOCKED, "锁定状态"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysUserStatus() { + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/model/constant/SysUserType.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/model/constant/SysUserType.java new file mode 100644 index 00000000..6958a002 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/model/constant/SysUserType.java @@ -0,0 +1,49 @@ +package com.orange.demo.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 用户类型常量字典对象。 + * + * @author Jerry + * @date 2020-09-24 + */ +public final class SysUserType { + + /** + * 管理员。 + */ + public static final int TYPE_ADMIN = 0; + /** + * 系统操作员。 + */ + public static final int TYPE_SYSTEM = 1; + /** + * 普通操作员。 + */ + public static final int TYPE_OPERATOR = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(TYPE_ADMIN, "管理员"); + DICT_MAP.put(TYPE_SYSTEM, "系统操作员"); + DICT_MAP.put(TYPE_OPERATOR, "普通操作员"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysUserType() { + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/service/SysUserService.java b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/service/SysUserService.java new file mode 100644 index 00000000..6d3f9e38 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/java/com/orange/demo/upms/service/SysUserService.java @@ -0,0 +1,175 @@ +package com.orange.demo.upms.service; + +import com.alibaba.fastjson.JSONObject; +import com.orange.demo.upms.dao.*; +import com.orange.demo.upms.model.*; +import com.orange.demo.upms.model.constant.SysUserStatus; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.constant.GlobalDeletedFlag; +import com.orange.demo.common.core.object.TokenData; +import com.orange.demo.common.core.object.MyWhereCriteria; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import tk.mybatis.mapper.entity.Example; + +import java.util.*; + +/** + * 用户管理数据操作服务类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Service +public class SysUserService extends BaseService { + + @Autowired + private SysUserMapper sysUserMapper; + @Autowired + private IdGeneratorWrapper idGenerator; + @Autowired + private PasswordEncoder passwordEncoder; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysUserMapper; + } + + /** + * 获取指定登录名的用户对象。 + * + * @param loginName 指定登录用户名。 + * @return 用户对象。 + */ + public SysUser getSysUserByLoginName(String loginName) { + Example e = new Example(SysUser.class); + Example.Criteria c = e.createCriteria(); + c.andEqualTo("loginName", loginName); + c.andEqualTo("deletedFlag", GlobalDeletedFlag.NORMAL); + return sysUserMapper.selectOneByExample(e); + } + + /** + * 保存新增的用户对象。 + * + * @param user 新增的用户对象。 + * @return 新增后的用户对象。 + */ + @Transactional(rollbackFor = Exception.class) + public SysUser saveNew(SysUser user) { + user.setUserId(idGenerator.nextLongId()); + user.setPassword(passwordEncoder.encode(user.getPassword())); + user.setUserStatus(SysUserStatus.STATUS_NORMAL); + user.setDeletedFlag(GlobalDeletedFlag.NORMAL); + TokenData tokenData = TokenData.takeFromRequest(); + user.setCreateUserId(tokenData.getUserId()); + user.setCreateUsername(tokenData.getShowName()); + Date now = new Date(); + user.setCreateTime(now); + user.setUpdateTime(now); + sysUserMapper.insert(user); + return user; + } + + /** + * 更新用户对象。 + * + * @param user 更新的用户对象。 + * @param originalUser 原有的用户对象。 + * @return 更新成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(SysUser user, SysUser originalUser) { + user.setLoginName(originalUser.getLoginName()); + user.setPassword(originalUser.getPassword()); + user.setCreateUserId(originalUser.getCreateUserId()); + user.setCreateUsername(originalUser.getCreateUsername()); + user.setCreateTime(originalUser.getCreateTime()); + user.setUpdateTime(new Date()); + return sysUserMapper.updateByPrimaryKeySelective(user) == 1; + } + + /** + * 修改用户密码。 + * @param userId 用户主键Id。 + * @param newPass 新密码。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean changePassword(Long userId, String newPass) { + Example e = new Example(SysUser.class); + e.createCriteria().andEqualTo(super.idFieldName, userId); + e.createCriteria().andEqualTo(super.deletedFlagFieldName, GlobalDeletedFlag.NORMAL); + SysUser updatedUser = new SysUser(); + updatedUser.setPassword(passwordEncoder.encode(newPass)); + return sysUserMapper.updateByExampleSelective(updatedUser, e) == 1; + } + + /** + * 删除指定数据。 + * + * @param userId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long userId) { + Example sysUserExample = new Example(SysUser.class); + Example.Criteria c = sysUserExample.createCriteria(); + c.andEqualTo(super.idFieldName, userId); + c.andEqualTo(super.deletedFlagFieldName, GlobalDeletedFlag.NORMAL); + // 这里先删除主数据 + SysUser deletedObject = new SysUser(); + deletedObject.setDeletedFlag(GlobalDeletedFlag.DELETED); + return sysUserMapper.updateByExampleSelective(deletedObject, sysUserExample) != 0; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getSysUserListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getSysUserList(SysUser filter, String orderBy) { + return sysUserMapper.getSysUserList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getSysUserList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getSysUserListWithRelation(SysUser filter, String orderBy) { + List resultList = sysUserMapper.getSysUserList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap); + return resultList; + } + + /** + * 验证用户对象关联的数据是否都合法。 + * + * @param sysUser 当前操作的对象。 + * @param originalSysUser 原有对象。 + * @return 验证结果。 + */ + public CallResult verifyRelatedData(SysUser sysUser, SysUser originalSysUser) { + JSONObject jsonObject = new JSONObject(); + return CallResult.ok(jsonObject); + } +} diff --git a/orange-demo-single-service-for-app/application/src/main/resources/application.yml b/orange-demo-single-service-for-app/application/src/main/resources/application.yml new file mode 100644 index 00000000..028012d2 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/resources/application.yml @@ -0,0 +1,202 @@ +logging: + level: + # 这里设置的日志级别优先于log4j2.xml文件Loggers中的日志级别。 + com.orange.demo: info + +server: + tomcat: + uri-encoding: UTF-8 + max-threads: 100 + min-spare-threads: 10 + port: 8082 + +# spring相关配置 +spring: + application: + name: application + profiles: + active: dev + servlet: + multipart: + max-file-size: 50MB + max-request-size: 50MB + http: + converters: + preferred-json-mapper: fastjson + encoding: + force: true + charset: UTF-8 + enabled: true + freemarker: + template-loader-path: classpath:/template/ + cache: false + charset: UTF-8 + check-template-location: true + content-type: text/html + expose-request-attributes: false + expose-session-attributes: false + request-context-attribute: request + suffix: .ftl + +# mybatis的基本配置 +mybatis: + mapperLocations: classpath:com/orange/demo/*/dao/mapper/*Mapper.xml + typeAliasesPackage: com.orange.demo.*.model + +# mybatis的通用mapper的配置 +mapper: + mappers: tk.mybatis.mapper.common.Mapper,tk.mybatis.mapper.additional.insert.InsertListMapper + not-empty: false + identity: MYSQL + +# 自动分页的配置 +pagehelper: + helperDialect: mysql + reasonable: true + supportMethodsArguments: false + params: count=countSql + +swagger: + # 当enabled为false的时候,则可禁用swagger。 + enabled: true + # 工程的基础包名。 + basePackage: com.orange.demo + title: 橙单单体开源版 + description: 橙单单体开源版详情 + version: 1.0 + +# 暴露监控端点 +management: + endpoints: + web: + exposure: + include: '*' + jmx: + exposure: + include: '*' + endpoint: + # 与中间件相关的健康详情也会被展示 + health: + show-details: always + configprops: + # 在/actuator/configprops中,所有包含password的配置,将用 * 隐藏。 + # 如果不想隐藏任何配置项的值,可以直接使用如下被注释的空值。 + # keys-to-sanitize: + keys-to-sanitize: password + server: + servlet: + context-path: "/" + +# 开发数据库相关配置 +--- +spring: + profiles: dev + datasource: + type: com.alibaba.druid.pool.DruidDataSource + druid: + url: jdbc:mysql://localhost:3306/zzdemo-single?characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai + username: root + password: 123456 + driver-class-name: com.mysql.cj.jdbc.Driver + name: application + initialSize: 10 + minIdle: 10 + maxActive: 50 + maxWait: 60000 + timeBetweenEvictionRunsMillis: 60000 + minEvictableIdleTimeMillis: 300000 + poolPreparedStatements: true + maxPoolPreparedStatementPerConnectionSize: 20 + maxOpenPreparedStatements: 20 + validationQuery: SELECT 'x' + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 + filters: stat,wall + useGlobalDataSourceStat: true + web-stat-filter: + enabled: true + url-pattern: /* + exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*,/actuator/*" + stat-view-servlet: + enabled: true + urlPattern: /druid/* + resetEnable: true + +application: + # Jwt令牌加密的签名值。该值的长度要超过10个字符(过短会报错)。 + tokenSigningKey: OrangeSingleDemo-signing-key + # Jwt令牌在Http Header中的键名称。 + tokenHeaderKey: Authorization + # Jwt令牌刷新后在Http Header中的键名称。 + refreshedTokenHeaderKey: RefreshedToken + # Jwt令牌过期时间(毫秒)。 + expiration: 72000000 + # 初始化密码。 + defaultUserPassword: 123456 + # 缺省的文件上传根目录。 + uploadFileBaseDir: ./zz-resource/upload-files/app + # 跨域的IP白名单列表,多个IP之间逗号分隔(* 表示全部信任,空白表示禁用跨域信任)。 + credentialIpList: "*" + +sequence: + # Snowflake 分布式Id生成算法所需的WorkNode参数值。 + snowflakeWorkNode: 1 + +# 发布数据库相关配置 +--- +spring: + profiles: product + datasource: + type: com.alibaba.druid.pool.DruidDataSource + druid: + url: jdbc:mysql://localhost:3306/zzdemo-single?characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai + username: root + password: 123456 + driver-class-name: com.mysql.cj.jdbc.Driver + name: application + initialSize: 10 + minIdle: 10 + maxActive: 50 + maxWait: 60000 + timeBetweenEvictionRunsMillis: 60000 + minEvictableIdleTimeMillis: 300000 + poolPreparedStatements: true + maxPoolPreparedStatementPerConnectionSize: 20 + maxOpenPreparedStatements: 20 + validationQuery: SELECT 'x' + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 + filters: stat,wall + useGlobalDataSourceStat: true + web-stat-filter: + enabled: true + url-pattern: /* + exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*,/actuator/*" + stat-view-servlet: + enabled: true + urlPattern: /druid/* + resetEnable: true + +application: + # Jwt令牌加密的签名值。该值的长度要超过10个字符(过短会报错)。 + tokenSigningKey: OrangeSingleDemo-signing-key + # Jwt令牌在Http Header中的键名称。 + tokenHeaderKey: Authorization + # Jwt令牌刷新后在Http Header中的键名称。 + refreshedTokenHeaderKey: RefreshedToken + # Jwt令牌过期时间(毫秒)。 + expiration: 72000000 + # 初始化密码。 + defaultUserPassword: 123456 + # 缺省的文件上传根目录。 + uploadFileBaseDir: ./zz-resource/upload-files/app + # 跨域的IP白名单列表,多个IP之间逗号分隔(* 表示全部信任,空白表示禁用跨域信任)。 + credentialIpList: "*" + +sequence: + # Snowflake 分布式Id生成算法所需的WorkNode参数值。 + snowflakeWorkNode: 1 diff --git a/orange-demo-single-service-for-app/application/src/main/resources/log4j2.xml b/orange-demo-single-service-for-app/application/src/main/resources/log4j2.xml new file mode 100644 index 00000000..ab205b9e --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/resources/log4j2.xml @@ -0,0 +1,73 @@ + + + + + + + + + + ./zzlogs + + ./zzlogs/backup + + info + + + + + + + + [%-5p] [%d{YYYY-MM-dd HH:mm:ss}] [%t] ==> %msg%n + + + [%-5p] [%d{YYYY-MM-dd HH:mm:ss}] 请求Id[%X{traceId}] [%t] ==> %msg%n + + + 31 + + 20M + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/orange-demo-single-service-for-app/application/src/main/resources/template/views/print_error.ftl b/orange-demo-single-service-for-app/application/src/main/resources/template/views/print_error.ftl new file mode 100644 index 00000000..af8b36a7 --- /dev/null +++ b/orange-demo-single-service-for-app/application/src/main/resources/template/views/print_error.ftl @@ -0,0 +1,329 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 天津公安警官职业学院2017—2018学年度第一学期课程表 + + + 班 级 + 星期一 + 星期二 + 星期三 + 星期四 + 星期五 + + + 第1节 + 第2节 + 第3节 + 第1节 + 第2节 + 第3节 + 第1节 + 第2节 + 第3节 + 第1节 + 第2节 + 第3节 + 第1节 + 第2节 + + + 16 级 刑 事 技 术 班 + 课程 + 刑法 + 自习 + 刑事图像 + 民 法(选修) + 派出所工作 + 刑事图像 + 法医学 + 派出所工作 + 法医学 + 国内安全保卫 + 体能 + 自习 + 刑事技术总论 + 刑法 + + + 自习 + 自习 + 自习 + + + 教师 + 曾岚 + 陈磊 + 邵刚 + 杨丽伟 + 陈磊 + 于辉 + 杨丽伟 + 于辉 + 朱学强 + 张付海 + 王 伟(刑技) + 曾岚 + + + + + + + + 教室 + 206 + 206 + 206 + 206 + 206 + 206 + 206 + 206 + 206 + 操场 + 206 + 206 + + + + + + + + 16 级 刑 事 侦 查 + 课程 + 自习 + 侦查措施 + 经济案件侦查 + 公安信息化 + 公安信息化 + 刑法 + 体能 + 自习 + 痕迹检验 + 刑法 + 国内安全保卫 + 经济案件侦查 + 痕迹检验 + 民 法(选修) + + + 侦查措施 + + + 教师 + 徐宏涛 + 张静 + 赵晓松 + 赵晓松 + 王骏强 + 张付海 + 郭海川 + 王骏强 + 朱学强 + 张静 + 郭海川 + 邵刚 + + + 徐宏涛 + + + 教室 + 202 + 202 + 3号机房 + 3号机房 + 202 + 操场 + 202 + 202 + 202 + 202 + 202 + 202 + + + + + 16 级 治 安 管 理 班 + 课程 + 刑事技术 + 体能 + 刑事技术 + 治安秩序管理 + 刑事侦查概论 + 刑法 + 群众工作与纠纷调解 + 群众工作与纠纷调解 + 公共关系(选修) + 刑事侦查概论 + 刑法 + 自习 + 自习 + 自习 + + + q + + + 教师 + 郭海川 韩易浦 + 张付海 + 郭海川 韩易浦 + 翟政亮 + 邵妍 + 薛强 + 刘晓鹏 + 刘晓鹏 + 尚欣 + 邵妍 + 薛强 + + + 翟政亮 + + + 教室 + 218 + 操场 + 218 + 218 + 218 + 218 + 218 + 218 + 218 + 218 + 218 + + + + + 16 网 络 安 全 监 察 1 班 + 课程 + 应用写作 + 数据库系统应用 + 周二中午:计算机安全管理及实用技术 + 刑事诉讼法 + 周一中午:数据库系统应用 + 民法 + 体育 + VB语言程序设计 + 选修 + VB语言程序设计 + 刑事诉讼法 + 选修 + 应用写作 + 犯罪心理 + + + 民法 + 犯罪心理 + + + 教师 + 关利 + 杨斌 + 赵晓松 + 王伟 + 杨斌 + 李静 + 程军 + 赵伟 + 赵伟 + 王伟 + 关利 + 张学林 + + + 李静 + 张学林 + + + 教室 + 东阶梯 + 2号机房 + 主楼201 + 101 + 2号机房 + 101 + 操场 + 3号机房 + 3号机房 + 101 + 东阶梯 + 主楼201 + + + 主楼201 + + + 注:1、课程一栏中有两科次的,上面的课程单周上课,下面的课程双周上课。2、每天上课时间:上午第1节8:30至9:55;第2节10:15至11:40;中午上课时间12:30至13:55;下午第3节14:00至15:25。 + + + + + diff --git a/orange-demo-single-service-for-app/common/common-core/pom.xml b/orange-demo-single-service-for-app/common/common-core/pom.xml new file mode 100644 index 00000000..f3e0cad6 --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/pom.xml @@ -0,0 +1,109 @@ + + + + com.orange.demo + common + 1.0.0 + + 4.0.0 + + common-core + 1.0.0 + common-core + jar + + + + + com.google.guava + guava + + + org.apache.commons + commons-lang3 + + + commons-codec + commons-codec + + + commons-io + commons-io + + + commons-fileupload + commons-fileupload + + + org.apache.httpcomponents + httpclient + + + joda-time + joda-time + + + org.apache.commons + commons-collections4 + ${commons-collections4.version} + + + org.apache.commons + commons-csv + ${common-csv.version} + + + cn.hutool + hutool-all + ${hutool.version} + + + io.jsonwebtoken + jjwt + ${jjwt.version} + + + com.alibaba + fastjson + ${fastjson.version} + + + com.github.ben-manes.caffeine + caffeine + ${caffeine.version} + + + cn.jimmyshi + bean-query + ${bean.query.version} + + + + org.apache.poi + poi-ooxml + ${poi-ooxml.version} + + + + mysql + mysql-connector-java + runtime + + + com.alibaba + druid-spring-boot-starter + ${druid.version} + + + tk.mybatis + mapper-spring-boot-starter + ${mybatis-mapper.version} + + + com.github.pagehelper + pagehelper-spring-boot-starter + ${pagehelper.version} + + + diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/advice/MyControllerAdvice.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/advice/MyControllerAdvice.java new file mode 100644 index 00000000..53d7e496 --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/advice/MyControllerAdvice.java @@ -0,0 +1,30 @@ +package com.orange.demo.common.core.advice; + +import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.InitBinder; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Controller的环绕拦截类。 + * + * @author Jerry + * @date 2020-09-24 + */ +@ControllerAdvice +public class MyControllerAdvice { + + /** + * 转换前端传入的日期变量参数为指定格式。 + * + * @param binder 数据绑定参数。 + */ + @InitBinder + public void initBinder(WebDataBinder binder) { + binder.registerCustomEditor(Date.class, + new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), false)); + } +} diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/advice/MyExceptionHandler.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/advice/MyExceptionHandler.java new file mode 100644 index 00000000..eec03f49 --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/advice/MyExceptionHandler.java @@ -0,0 +1,131 @@ +package com.orange.demo.common.core.advice; + +import com.orange.demo.common.core.exception.InvalidClassFieldException; +import com.orange.demo.common.core.exception.InvalidDataFieldException; +import com.orange.demo.common.core.exception.InvalidDataModelException; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.exception.RedisCacheAccessException; +import com.orange.demo.common.core.object.ResponseResult; +import com.orange.demo.common.core.util.ContextUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.exceptions.PersistenceException; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.dao.PermissionDeniedDataAccessException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.concurrent.TimeoutException; + +/** + * 业务层的异常处理类,这里只是给出最通用的Exception的捕捉,今后可以根据业务需要, + * 用不同的函数,处理不同类型的异常。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Slf4j +@RestControllerAdvice("com.orange.demo") +public class MyExceptionHandler { + + /** + * 通用异常处理方法。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = Exception.class) + public ResponseResult exceptionHandle(Exception ex, HttpServletRequest request) { + log.error("Unhandled exception from URL [" + request.getRequestURI() + "]", ex); + ContextUtil.getHttpResponse().setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + return ResponseResult.error(ErrorCodeEnum.UNHANDLED_EXCEPTION, ex.getMessage()); + } + + /** + * 无效的实体对象异常。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = InvalidDataModelException.class) + public ResponseResult invalidDataModelExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("InvalidDataModelException exception from URL [" + request.getRequestURI() + "]", ex); + return ResponseResult.error(ErrorCodeEnum.INVALID_DATA_MODEL); + } + + /** + * 无效的实体对象字段异常。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = InvalidDataFieldException.class) + public ResponseResult invalidDataFieldExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("InvalidDataFieldException exception from URL [" + request.getRequestURI() + "]", ex); + return ResponseResult.error(ErrorCodeEnum.INVALID_DATA_FIELD); + } + + /** + * 无效类字段异常。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = InvalidClassFieldException.class) + public ResponseResult invalidClassFieldExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("InvalidClassFieldException exception from URL [" + request.getRequestURI() + "]", ex); + return ResponseResult.error(ErrorCodeEnum.INVALID_CLASS_FIELD); + } + + /** + * 重复键异常处理方法。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = DuplicateKeyException.class) + public ResponseResult duplicateKeyExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("DuplicateKeyException exception from URL [" + request.getRequestURI() + "]", ex); + return ResponseResult.error(ErrorCodeEnum.DUPLICATED_UNIQUE_KEY); + } + + /** + * 数据访问失败异常处理方法。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = DataAccessException.class) + public ResponseResult dataAccessExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("DataAccessException exception from URL [" + request.getRequestURI() + "]", ex); + if (ex.getCause() instanceof PersistenceException + && ex.getCause().getCause() instanceof PermissionDeniedDataAccessException) { + return ResponseResult.error(ErrorCodeEnum.DATA_PERM_ACCESS_FAILED); + } + return ResponseResult.error(ErrorCodeEnum.DATA_ACCESS_FAILED); + } + + /** + * Redis缓存访问异常处理方法。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = RedisCacheAccessException.class) + public ResponseResult redisCacheAccessExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("RedisCacheAccessException exception from URL [" + request.getRequestURI() + "]", ex); + if (ex.getCause() instanceof TimeoutException) { + return ResponseResult.error(ErrorCodeEnum.REDIS_CACHE_ACCESS_TIMEOUT); + } + return ResponseResult.error(ErrorCodeEnum.REDIS_CACHE_ACCESS_STATE_ERROR); + } +} diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/DeletedFlagColumn.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/DeletedFlagColumn.java new file mode 100644 index 00000000..f7d0caaa --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/DeletedFlagColumn.java @@ -0,0 +1,16 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记逻辑删除字段。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DeletedFlagColumn { + +} diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/JobUpdateTimeColumn.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/JobUpdateTimeColumn.java new file mode 100644 index 00000000..fcf2a6e2 --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/JobUpdateTimeColumn.java @@ -0,0 +1,16 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记更新字段。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface JobUpdateTimeColumn { + +} diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/MyDataSource.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/MyDataSource.java new file mode 100644 index 00000000..a8eba077 --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/MyDataSource.java @@ -0,0 +1,21 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记Service所依赖的数据源类型。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface MyDataSource { + + /** + * 标注的数据源类型 + * @return 当前标注的数据源类型。 + */ + int value(); +} diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/MyRequestBody.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/MyRequestBody.java new file mode 100644 index 00000000..cb52d6d5 --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/MyRequestBody.java @@ -0,0 +1,31 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 标记Controller中的方法参数,参数解析器会根据该注解将请求中的JSON数据,映射到参数中的绑定字段。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface MyRequestBody { + + /** + * 是否必须出现的参数。 + */ + boolean required() default false; + /** + * 解析时用到的JSON的key。 + */ + String value() default ""; + /** + * 集合元素的ClassType。只有在接口参数为List的时候,需要把E的class传入。 + * 缺省值Class.class表示没有设置。 + */ + Class> elementType() default Class.class; +} \ No newline at end of file diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/NoAuthInterface.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/NoAuthInterface.java new file mode 100644 index 00000000..54a7bdff --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/NoAuthInterface.java @@ -0,0 +1,15 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记无需Token验证的接口 + * + * @author Jerry + * @date 2020-09-24 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface NoAuthInterface { +} diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationConstDict.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationConstDict.java new file mode 100644 index 00000000..658b6bdb --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationConstDict.java @@ -0,0 +1,29 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 标识Model和常量字典之间的关联关系。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationConstDict { + + /** + * 当前对象的关联Id字段名称。 + * + * @return 当前对象的关联Id字段名称。 + */ + String masterIdField(); + + /** + * 被关联的常量字典的Class对象。 + * + * @return 关联的常量字典的Class对象。 + */ + Class> constantDictClass(); +} diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationDict.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationDict.java new file mode 100644 index 00000000..77dfea33 --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationDict.java @@ -0,0 +1,60 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 标识Model之间的字典关联关系。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationDict { + + /** + * 当前对象的关联Id字段名称。 + * + * @return 当前对象的关联Id字段名称。 + */ + String masterIdField(); + + /** + * 被关联Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class> slaveModelClass(); + + /** + * 被关联Model对象的关联Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String slaveIdField(); + + /** + * 被关联Model对象的关联Name字段名称。 + * + * @return 被关联Model对象的关联Name字段名称。 + */ + String slaveNameField(); + + /** + * 被关联的本地Service对象名称。 + * + * @return 被关联的本地Service对象名称。 + */ + String slaveServiceName(); + + /** + * 在同一个实体对象中,如果有一对一关联和字典关联,都是基于相同的主表字段,并关联到 + * 相同关联表的同一关联字段时,可以在字典关联的注解中引用被一对一注解标准的对象属性。 + * 从而在数据整合时,当前字典的数据可以直接取自"equalOneToOneRelationField"指定 + * 的字段,从而避免一次没必要的数据库查询操作,提升了加载显示的效率。 + * + * @return 与该字典字段引用关系完全相同的一对一关联属性名称。 + */ + String equalOneToOneRelationField() default ""; +} diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationManyToMany.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationManyToMany.java new file mode 100644 index 00000000..2cf58252 --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationManyToMany.java @@ -0,0 +1,38 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 标注多对多的Model关系。 + * 重要提示:由于多对多关联表数据,很多时候都不需要跟随主表数据返回,所以该注解不会在 + * 生成的时候自动添加到实体类字段上,需要的时候,用户可自行手动添加。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationManyToMany { + + /** + * 多对多中间表的Mapper对象名称。 + * + * @return 被关联的本地Service对象名称。 + */ + String relationMapperName(); + + /** + * 多对多关联表Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class> relationModelClass(); + + /** + * 多对多关联表Model对象中与主表关联的Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String relationMasterIdField(); +} diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationManyToManyAggregation.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationManyToManyAggregation.java new file mode 100644 index 00000000..25ab5f77 --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationManyToManyAggregation.java @@ -0,0 +1,85 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于多对多的Model关系。标注通过从表关联字段或者关联表关联字段计算主表聚合计算字段的规则。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationManyToManyAggregation { + + /** + * 当前对象的关联Id字段名称。 + * + * @return 当前对象的关联Id字段名称。 + */ + String masterIdField(); + + /** + * 被关联的本地Service对象名称。 + * + * @return 被关联的本地Service对象名称。 + */ + String slaveServiceName(); + + /** + * 多对多从表Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class> slaveModelClass(); + + /** + * 多对多从表Model对象的关联Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String slaveIdField(); + + /** + * 多对多关联表Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class> relationModelClass(); + + /** + * 多对多关联表Model对象中与主表关联的Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String relationMasterIdField(); + + /** + * 多对多关联表Model对象中与从表关联的Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String relationSlaveIdField(); + + /** + * 聚合计算所在的Model。 + * + * @return 聚合计算所在Model的Class。 + */ + Class> aggregationModelClass(); + + /** + * 聚合类型。具体数值参考AggregationType对象。 + * + * @return 聚合类型。 + */ + int aggregationType(); + + /** + * 聚合计算所在Model的字段名称。 + * + * @return 聚合计算所在Model的字段名称。 + */ + String aggregationField(); +} diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationOneToManyAggregation.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationOneToManyAggregation.java new file mode 100644 index 00000000..c688f6be --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationOneToManyAggregation.java @@ -0,0 +1,57 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于一对多的Model关系。标注通过从表关联字段计算主表聚合计算字段的规则。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationOneToManyAggregation { + + /** + * 当前对象的关联Id字段名称。 + * + * @return 当前对象的关联Id字段名称。 + */ + String masterIdField(); + + /** + * 被关联的本地Service对象名称。 + * + * @return 被关联的本地Service对象名称。 + */ + String slaveServiceName(); + + /** + * 被关联Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class> slaveModelClass(); + + /** + * 被关联Model对象的关联Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String slaveIdField(); + + /** + * 被关联Model对象中参与计算的聚合类型。具体数值参考AggregationType对象。 + * + * @return 被关联Model对象中参与计算的聚合类型。 + */ + int aggregationType(); + + /** + * 被关联Model对象中参与聚合计算的字段名称。 + * + * @return 被关联Model对象中参与计算字段的名称。 + */ + String aggregationField(); +} diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationOneToOne.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationOneToOne.java new file mode 100644 index 00000000..616843a1 --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationOneToOne.java @@ -0,0 +1,50 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 标识Model之间的一对一关联关系。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationOneToOne { + + /** + * 当前对象的关联Id字段名称。 + * + * @return 当前对象的关联Id字段名称。 + */ + String masterIdField(); + + /** + * 被关联Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class> slaveModelClass(); + + /** + * 被关联Model对象的关联Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String slaveIdField(); + + /** + * 被关联的本地Service对象名称。 + * + * @return 被关联的本地Service对象名称。 + */ + String slaveServiceName(); + + /** + * 在一对一关联时,是否加载从表的字典关联。 + * + * @return 是否加载从表的字典关联。true关联,false则只返回从表自身数据。 + */ + boolean loadSlaveDict() default true; +} diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/UploadFlagColumn.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/UploadFlagColumn.java new file mode 100644 index 00000000..dd308cbe --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/annotation/UploadFlagColumn.java @@ -0,0 +1,24 @@ +package com.orange.demo.common.core.annotation; + +import com.orange.demo.common.core.upload.UploadStoreTypeEnum; + +import java.lang.annotation.*; + +/** + * 用于标记支持数据上传和下载的字段。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface UploadFlagColumn { + + /** + * 上传数据存储类型。 + * + * @return 上传数据存储类型。 + */ + UploadStoreTypeEnum storeType(); +} diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/aop/AccessLogAspect.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/aop/AccessLogAspect.java new file mode 100644 index 00000000..638b0d26 --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/aop/AccessLogAspect.java @@ -0,0 +1,82 @@ +package com.orange.demo.common.core.aop; + +import com.alibaba.fastjson.JSON; +import com.orange.demo.common.core.constant.ApplicationConstant; +import com.orange.demo.common.core.util.MyCommonUtil; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.slf4j.MDC; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; + +/** + * 记录接口的链路traceId、请求参数、应答数据、错误信息和调用时长。 + * + * @author Jerry + * @date 2020-09-24 + */ +@Aspect +@Component +@Order(1) +@Slf4j +public class AccessLogAspect { + + /** + * 所有controller方法。 + */ + @Pointcut("execution(public * com.orange.demo..controller..*(..))") + public void controllerPointCut() { + // 空注释,避免sonar警告 + } + + @Around("controllerPointCut()") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + HttpServletRequest request = + ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + // 请求流水号 + String traceId = MyCommonUtil.generateUuid(); + HttpServletResponse response = + ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getResponse(); + response.setHeader(ApplicationConstant.HTTP_HEADER_TRACE_ID, traceId); + MDC.put(ApplicationConstant.HTTP_HEADER_TRACE_ID, traceId); + long start = System.currentTimeMillis(); + // 获取方法参数 + List httpReqArgs = new ArrayList<>(); + Object[] args = joinPoint.getArgs(); + for (Object object : args) { + if (!(object instanceof HttpServletRequest) + && !(object instanceof HttpServletResponse) + && !(object instanceof MultipartFile)) { + httpReqArgs.add(object); + } + } + String url = request.getRequestURI(); + String params = JSON.toJSONString(httpReqArgs); + log.info("开始请求,traceId={}, url={}, reqData={}", traceId, url, params); + Object result = null; + try { + // 调用原来的方法 + result = joinPoint.proceed(); + } catch (Exception e) { + log.error("请求报错,traceId={}, url={}, reqData={}, error={}", traceId, url, params, e.getMessage()); + throw e; + } finally { + // 获取应答报文及接口处理耗时 + String respData = result == null ? null : JSON.toJSONString(result); + log.info("请求完成, traceId={}, url={},elapse={}ms, respData={}", + traceId, url, (System.currentTimeMillis() - start), respData); + } + return result; + } +} \ No newline at end of file diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/base/dao/BaseDaoMapper.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/base/dao/BaseDaoMapper.java new file mode 100644 index 00000000..c1e65a9d --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/base/dao/BaseDaoMapper.java @@ -0,0 +1,90 @@ +package com.orange.demo.common.core.base.dao; + +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import tk.mybatis.mapper.additional.insert.InsertListMapper; +import tk.mybatis.mapper.annotation.RegisterMapper; +import tk.mybatis.mapper.common.Mapper; + +import java.util.List; +import java.util.Map; + +/** + * 数据访问对象的基类。 + * + * @param 主Model实体对象。 + * @author Jerry + * @date 2020-09-24 + */ +@RegisterMapper +public interface BaseDaoMapper extends Mapper, InsertListMapper { + + /** + * 根据指定的表名、显示字段列表、过滤条件字符串和分组字段,返回聚合计算后的查询结果。 + * + * @param selectTable 表名称。 + * @param selectFields 返回字段列表,逗号分隔。 + * @param whereClause SQL常量形式的条件从句。 + * @param groupBy 分组字段列表,逗号分隔。 + * @return 对象可选字段Map列表。 + */ + @Select("") + List> getGroupedListByCondition( + @Param("selectTable") String selectTable, + @Param("selectFields") String selectFields, + @Param("whereClause") String whereClause, + @Param("groupBy") String groupBy); + + /** + * 根据指定的表名、显示字段列表、过滤条件字符串和排序字符串,返回查询结果。 + * + * @param selectTable 表名称。 + * @param selectFields 选择的字段列表。 + * @param whereClause 过滤字符串。 + * @param orderBy 排序字符串。 + * @return 查询结果。 + */ + @Select("") + List> getListByCondition( + @Param("selectTable") String selectTable, + @Param("selectFields") String selectFields, + @Param("whereClause") String whereClause, + @Param("orderBy") String orderBy); + + /** + * 用指定过滤条件,计算记录数量。 + * + * @param selectTable 表名称。 + * @param whereClause 过滤字符串。 + * @return 返回过滤后的数据数量。 + */ + @Select("") + int getCountByCondition(@Param("selectTable") String selectTable, @Param("whereClause") String whereClause); +} diff --git a/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/base/mapper/BaseModelMapper.java b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/base/mapper/BaseModelMapper.java new file mode 100644 index 00000000..42be1057 --- /dev/null +++ b/orange-demo-single-service-for-app/common/common-core/src/main/java/com/orange/demo/common/core/base/mapper/BaseModelMapper.java @@ -0,0 +1,124 @@ +package com.orange.demo.common.core.base.mapper; + +import cn.hutool.core.bean.BeanUtil; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Model对象到Domain类型对象的相互转换。实现类通常声明在Model实体类中。 + * + * @param Domain域对象类型。 + * @param Model实体对象类型。 + * @author Jerry + * @date 2020-09-24 + */ +public interface BaseModelMapper { + + /** + * 转换Model实体对象到Domain域对象。 + * + * @param model Model实体对象。 + * @return Domain域对象。 + */ + D fromModel(M model); + + /** + * 转换Model实体对象列表到Domain域对象列表。 + * + * @param modelList Model实体对象列表。 + * @return Domain域对象列表。 + */ + List fromModelList(List modelList); + + /** + * 转换Domain域对象到Model实体对象。 + * + * @param domain Domain域对象。 + * @return Model实体对象。 + */ + M toModel(D domain); + + /** + * 转换Domain域对象列表到Model实体对象列表。 + * + * @param domainList Domain域对象列表。 + * @return Model实体对象列表。 + */ + List toModelList(List domainList); + + /** + * 转换bean到map + * + * @param bean bean对象。 + * @param ignoreNullValue 值为null的字段是否转换到Map。 + * @param bean类型。 + * @return 转换后的map对象。 + */ + default