├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── admin-ui ├── .gitignore ├── README.md ├── jest.config.js ├── jest.setup.ts ├── jest │ └── map.test.ts ├── mocks │ ├── product.ts │ ├── tsconfig.json │ └── user.ts ├── package.json ├── public │ ├── captcha.jpeg │ ├── favicon.ico │ ├── index.html │ └── logo.png ├── react-jest.md ├── scripts │ ├── .gitignore │ ├── deploy.sh │ ├── docker-compose.yaml │ ├── install.sh │ └── package.sh ├── src │ ├── api │ │ ├── account.ts │ │ ├── flow.ts │ │ ├── index.ts │ │ ├── jar.ts │ │ ├── leave.ts │ │ ├── oss.ts │ │ ├── product.ts │ │ ├── typings.d.ts │ │ └── user.ts │ ├── assets │ │ └── logo.svg │ ├── components │ │ ├── flow │ │ │ ├── PostponedFormView.tsx │ │ │ ├── UserSelectView.tsx │ │ │ └── register.tsx │ │ └── icons │ │ │ └── index.tsx │ ├── config │ │ ├── menus.tsx │ │ ├── register.component.tsx │ │ └── theme.tsx │ ├── declarations.d.ts │ ├── framework │ │ ├── DynamicLoad │ │ │ ├── DynamicCode.tsx │ │ │ └── PageLoader.tsx │ │ ├── Permission │ │ │ ├── AccessProvider │ │ │ │ ├── handler.ts │ │ │ │ └── index.tsx │ │ │ └── RoleKeyProvider │ │ │ │ ├── RoleKeyManager.ts │ │ │ │ └── index.tsx │ │ └── Routes │ │ │ ├── MenuRouteManager.tsx │ │ │ └── RoutesProvider.tsx │ ├── gateway │ │ ├── default │ │ │ └── Header.tsx │ │ └── index.tsx │ ├── index.tsx │ ├── jest.setup.ts │ ├── layout │ │ ├── AvatarHeader │ │ │ └── index.tsx │ │ ├── HeaderAction │ │ │ └── index.tsx │ │ ├── HeaderDropdown │ │ │ └── index.tsx │ │ ├── NotFound │ │ │ └── index.tsx │ │ ├── index.scss │ │ └── index.tsx │ ├── pages │ │ ├── flow │ │ │ ├── leave │ │ │ │ ├── LeaveForm.tsx │ │ │ │ └── index.tsx │ │ │ ├── record │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── user │ │ │ │ ├── index.tsx │ │ │ │ └── select.tsx │ │ │ └── work │ │ │ │ ├── index.tsx │ │ │ │ └── select.tsx │ │ ├── form │ │ │ └── index.tsx │ │ ├── login │ │ │ └── index.tsx │ │ ├── mirco │ │ │ └── index.tsx │ │ └── welcome │ │ │ ├── index.scss │ │ │ └── index.tsx │ ├── react-app-env.d.ts │ ├── reportWebVitals.ts │ ├── store │ │ ├── CounterSlice.ts │ │ ├── MenuSlice.ts │ │ └── Redux.tsx │ ├── styles │ │ ├── index.scss │ │ ├── mixins.scss │ │ └── variable.scss │ └── utils │ │ ├── captcha.ts │ │ └── oss.ts ├── tsconfig.json ├── webpack.common.js ├── webpack.config.dev.js ├── webpack.config.mock.js └── webpack.config.prod.js ├── codecov.yml ├── docs ├── img │ └── ddd_architecture.png └── wiki │ ├── home.md │ ├── springboot-starter-data-authorization.md │ ├── springboot-starter-data-fast.md │ ├── springboot-starter-security.md │ └── springboot-starter.md ├── event.md ├── example ├── example-app │ ├── example-app-cmd-domain │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── codingapi │ │ │ └── example │ │ │ └── app │ │ │ └── cmd │ │ │ └── domain │ │ │ ├── configuration │ │ │ ├── LeaveDomainConfiguration.java │ │ │ └── UserDomainConfiguration.java │ │ │ ├── pojo │ │ │ └── UserCmd.java │ │ │ └── router │ │ │ └── UserRouter.java │ ├── example-app-cmd-meta │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── codingapi │ │ │ └── example │ │ │ └── app │ │ │ └── cmd │ │ │ └── meta │ │ │ ├── pojo │ │ │ ├── FlowCmd.java │ │ │ └── FlowWorkCmd.java │ │ │ └── service │ │ │ ├── FlowRecordRouter.java │ │ │ └── FlowWorkRouter.java │ ├── example-app-query │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── codingapi │ │ │ └── example │ │ │ └── app │ │ │ └── query │ │ │ └── service │ │ │ ├── FlowAppQueryService.java │ │ │ ├── FlowRecordQueryService.java │ │ │ ├── FlowWorkQueryService.java │ │ │ ├── LeaveAppQueryService.java │ │ │ ├── LeaveQueryService.java │ │ │ └── UserQueryService.java │ └── pom.xml ├── example-domain │ ├── example-domain-leave │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── codingapi │ │ │ └── example │ │ │ └── domain │ │ │ └── leave │ │ │ ├── entity │ │ │ └── Leave.java │ │ │ ├── repository │ │ │ └── LeaveRepository.java │ │ │ └── service │ │ │ └── LeaveService.java │ ├── example-domain-user │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── codingapi │ │ │ └── example │ │ │ └── domain │ │ │ └── user │ │ │ ├── entity │ │ │ ├── User.java │ │ │ └── UserMetric.java │ │ │ ├── event │ │ │ └── UserEvent.java │ │ │ ├── gateway │ │ │ └── PasswordEncoder.java │ │ │ ├── repository │ │ │ └── UserRepository.java │ │ │ └── service │ │ │ └── UserService.java │ └── pom.xml ├── example-infra │ ├── example-infra-flow │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── codingapi │ │ │ └── example │ │ │ └── infra │ │ │ └── flow │ │ │ ├── AutoFlowConfiguration.java │ │ │ ├── convert │ │ │ ├── BindDataSnapshotConvertor.java │ │ │ ├── FlowBackupConvertor.java │ │ │ ├── FlowNodeConvertor.java │ │ │ ├── FlowProcessConvertor.java │ │ │ ├── FlowRecordConvertor.java │ │ │ ├── FlowRelationConvertor.java │ │ │ └── FlowWorkConvertor.java │ │ │ ├── entity │ │ │ ├── BindDataSnapshotEntity.java │ │ │ ├── FlowBackupEntity.java │ │ │ ├── FlowNodeEntity.java │ │ │ ├── FlowProcessEntity.java │ │ │ ├── FlowRecordEntity.java │ │ │ ├── FlowRelationEntity.java │ │ │ └── FlowWorkEntity.java │ │ │ ├── form │ │ │ └── LeaveForm.java │ │ │ ├── jpa │ │ │ ├── BindDataSnapshotEntityRepository.java │ │ │ ├── FlowBackupEntityRepository.java │ │ │ ├── FlowNodeEntityRepository.java │ │ │ ├── FlowProcessEntityRepository.java │ │ │ ├── FlowRecordEntityRepository.java │ │ │ ├── FlowRelationEntityRepository.java │ │ │ └── FlowWorkEntityRepository.java │ │ │ ├── query │ │ │ └── FlowRecordQueryImpl.java │ │ │ ├── repository │ │ │ ├── FlowBackupRepositoryImpl.java │ │ │ ├── FlowBindDataRepositoryImpl.java │ │ │ ├── FlowProcessRepositoryImpl.java │ │ │ ├── FlowRecordRepositoryImpl.java │ │ │ └── FlowWorkRepositoryImpl.java │ │ │ └── user │ │ │ ├── FlowUser.java │ │ │ └── FlowUserRepository.java │ ├── example-infra-jpa │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── codingapi │ │ │ └── example │ │ │ └── infra │ │ │ └── db │ │ │ ├── convert │ │ │ ├── LeaveConvertor.java │ │ │ └── UserConvertor.java │ │ │ ├── entity │ │ │ ├── LeaveEntity.java │ │ │ ├── TestEntity.java │ │ │ └── UserEntity.java │ │ │ ├── jpa │ │ │ ├── LeaveEntityRepository.java │ │ │ ├── TestEntityRepository.java │ │ │ └── UserEntityRepository.java │ │ │ └── repository │ │ │ ├── LeaveRepositoryImpl.java │ │ │ └── UserRepositoryImpl.java │ ├── example-infra-security │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── codingapi │ │ │ └── example │ │ │ └── infra │ │ │ └── security │ │ │ ├── gateway │ │ │ └── PasswordEncoderImpl.java │ │ │ └── service │ │ │ └── UserDetailServiceImpl.java │ └── pom.xml ├── example-interface │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── codingapi │ │ └── example │ │ ├── api │ │ ├── domain │ │ │ └── UserDomainCmdController.java │ │ ├── meta │ │ │ ├── FlowRecordCmdController.java │ │ │ └── FlowWorkCmdController.java │ │ └── query │ │ │ ├── FlowRecordQueryController.java │ │ │ ├── FlowWorkQueryController.java │ │ │ ├── LeaveQueryController.java │ │ │ ├── UserQueryController.java │ │ │ └── app │ │ │ ├── FlowAppQueryController.java │ │ │ └── LeaveAppQueryController.java │ │ ├── handler │ │ └── LeaveHandler.java │ │ └── runner │ │ └── UserRunner.java ├── example-server │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── codingapi │ │ │ └── example │ │ │ └── ServerApplication.java │ │ └── resources │ │ └── application.properties └── pom.xml ├── mobile-ui ├── .gitignore ├── jest.config.js ├── jest.setup.ts ├── jest │ └── map.test.ts ├── mocks │ ├── product.ts │ ├── tsconfig.json │ └── user.ts ├── package.json ├── public │ ├── captcha.jpeg │ ├── favicon.ico │ ├── index.html │ └── logo.png ├── readme.md ├── scripts │ ├── .gitignore │ ├── deploy.sh │ ├── docker-compose.yaml │ ├── install.sh │ └── package.sh ├── src │ ├── api │ │ ├── account.ts │ │ ├── flow.ts │ │ ├── index.ts │ │ ├── leave.ts │ │ └── oss.ts │ ├── assets │ │ └── flow │ │ │ ├── done.png │ │ │ ├── todo.png │ │ │ └── un_submit.png │ ├── components │ │ ├── flow │ │ │ ├── PostponedFormView.tsx │ │ │ ├── UserSelectFormView.tsx │ │ │ └── register.tsx │ │ └── info │ │ │ ├── BasicInfo │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ │ ├── FormInfo │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ │ └── List │ │ │ ├── Item.tsx │ │ │ ├── index.scss │ │ │ └── index.tsx │ ├── config │ │ ├── flows.tsx │ │ ├── register.component.tsx │ │ ├── route.tsx │ │ └── theme.tsx │ ├── declarations.d.ts │ ├── gateway │ │ ├── default │ │ │ └── Header.tsx │ │ └── index.tsx │ ├── index.tsx │ ├── layout │ │ ├── Footer │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── Header │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── NotFound │ │ │ └── index.tsx │ │ └── index.tsx │ ├── pages │ │ ├── flow │ │ │ ├── detail.tsx │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── form │ │ │ └── index.tsx │ │ ├── home │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── leave │ │ │ ├── create.tsx │ │ │ ├── detail.tsx │ │ │ ├── fields.ts │ │ │ ├── form.tsx │ │ │ └── index.tsx │ │ ├── login │ │ │ └── index.tsx │ │ └── mirco │ │ │ └── index.tsx │ ├── reportWebVitals.ts │ ├── sotre │ │ └── LayoutSlice.ts │ ├── styles │ │ ├── index.scss │ │ ├── mixins.scss │ │ └── variable.scss │ └── utils │ │ └── oss.ts ├── tsconfig.json ├── webpack.common.js ├── webpack.config.dev.js ├── webpack.config.mock.js └── webpack.config.prod.js ├── mvnw ├── mvnw.cmd ├── pom.xml ├── springboot-starter-data-authorization ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── codingapi │ │ │ └── springboot │ │ │ └── authorization │ │ │ ├── DataAuthorizationConfiguration.java │ │ │ ├── DataAuthorizationContext.java │ │ │ ├── enhancer │ │ │ ├── DataPermissionSQLEnhancer.java │ │ │ ├── TableColumnAlias.java │ │ │ ├── TableColumnAliasContext.java │ │ │ └── TableColumnAliasHolder.java │ │ │ ├── exception │ │ │ └── NotAuthorizationException.java │ │ │ ├── filter │ │ │ ├── DataAuthorizationFilter.java │ │ │ └── DefaultDataAuthorizationFilter.java │ │ │ ├── handler │ │ │ ├── ColumnHandler.java │ │ │ ├── ColumnHandlerContext.java │ │ │ ├── Condition.java │ │ │ ├── DefaultColumnHandler.java │ │ │ ├── DefaultRowHandler.java │ │ │ ├── RowHandler.java │ │ │ └── RowHandlerContext.java │ │ │ ├── interceptor │ │ │ ├── DataPermissionSQL.java │ │ │ ├── DefaultSQLInterceptor.java │ │ │ ├── SQLInterceptState.java │ │ │ ├── SQLInterceptor.java │ │ │ ├── SQLInterceptorContext.java │ │ │ └── SQLRunningContext.java │ │ │ ├── jdbc │ │ │ ├── AuthorizationJdbcDriver.java │ │ │ └── proxy │ │ │ │ ├── CallableStatementProxy.java │ │ │ │ ├── ConnectionProxy.java │ │ │ │ ├── PreparedStatementProxy.java │ │ │ │ ├── ResultSetProxy.java │ │ │ │ └── StatementProxy.java │ │ │ ├── mask │ │ │ ├── ColumnMask.java │ │ │ ├── ColumnMaskContext.java │ │ │ └── impl │ │ │ │ ├── BankCardMask.java │ │ │ │ ├── IDCardMask.java │ │ │ │ └── PhoneMask.java │ │ │ ├── properties │ │ │ ├── DataAuthorizationProperties.java │ │ │ └── DataAuthorizationPropertyContext.java │ │ │ ├── register │ │ │ ├── ConditionHandlerRegister.java │ │ │ ├── DataAuthorizationContextRegister.java │ │ │ ├── ResultSetHandlerRegister.java │ │ │ └── SQLInterceptorRegister.java │ │ │ └── utils │ │ │ └── SQLUtils.java │ └── resources │ │ └── META-INF │ │ └── spring │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ └── test │ ├── java │ └── com │ │ └── codingapi │ │ └── springboot │ │ └── authorization │ │ ├── DataAuthorizationContextTest.java │ │ ├── DataAuthorizationTestApplication.java │ │ ├── analyzer │ │ └── SelectSQLAnalyzerTest.java │ │ ├── current │ │ └── CurrentUser.java │ │ ├── entity │ │ ├── Depart.java │ │ ├── Unit.java │ │ └── User.java │ │ ├── mask │ │ └── impl │ │ │ ├── BankCardMaskTest.java │ │ │ ├── IDCardMaskTest.java │ │ │ └── PhoneMaskTest.java │ │ └── repository │ │ ├── DepartRepository.java │ │ ├── UnitRepository.java │ │ └── UserRepository.java │ └── resources │ └── application.properties ├── springboot-starter-data-fast ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── codingapi │ │ │ └── springboot │ │ │ └── fast │ │ │ ├── DataFastConfiguration.java │ │ │ ├── jdbc │ │ │ ├── JdbcQuery.java │ │ │ ├── JdbcQueryConfiguration.java │ │ │ ├── JdbcQueryContext.java │ │ │ └── JdbcQueryContextRegister.java │ │ │ ├── jpa │ │ │ ├── JPAQuery.java │ │ │ ├── JPAQueryConfiguration.java │ │ │ ├── JPAQueryContextRegister.java │ │ │ ├── JpaQueryContext.java │ │ │ ├── SQLBuilder.java │ │ │ └── repository │ │ │ │ ├── BaseRepository.java │ │ │ │ ├── DynamicNativeRepository.java │ │ │ │ ├── DynamicRepository.java │ │ │ │ ├── DynamicSQLBuilder.java │ │ │ │ ├── ExampleBuilder.java │ │ │ │ ├── FastRepository.java │ │ │ │ └── SortRepository.java │ │ │ ├── manager │ │ │ ├── EntityManagerContent.java │ │ │ └── EntityManagerInitializer.java │ │ │ ├── mapping │ │ │ └── FastMvcMappingRegister.java │ │ │ └── script │ │ │ ├── FastScriptMappingRegister.java │ │ │ ├── ScriptMapping.java │ │ │ ├── ScriptMethod.java │ │ │ ├── ScriptRequest.java │ │ │ └── ScriptRuntime.java │ └── resources │ │ └── META-INF │ │ ├── spring.factories │ │ └── spring │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ └── test │ ├── java │ └── com │ │ └── codingapi │ │ └── springboot │ │ └── fast │ │ ├── DataFastApplication.java │ │ ├── DemoRepositoryTest.java │ │ ├── MenuRepositoryTest.java │ │ ├── UserRepositoryTest.java │ │ ├── entity │ │ ├── Demo.java │ │ ├── Menu.java │ │ ├── Profile.java │ │ └── User.java │ │ ├── repository │ │ ├── DemoRepository.java │ │ ├── MenuRepository.java │ │ ├── ProfileRepository.java │ │ └── UserRepository.java │ │ └── script │ │ └── ScriptRuntimeTest.java │ └── resources │ └── application.properties ├── springboot-starter-flow ├── README.md ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── codingapi │ │ │ └── springboot │ │ │ └── flow │ │ │ ├── FlowConfiguration.java │ │ │ ├── FlowFrameworkRegister.java │ │ │ ├── bind │ │ │ ├── BindDataSnapshot.java │ │ │ ├── FlowMapBindData.java │ │ │ └── IBindData.java │ │ │ ├── build │ │ │ ├── FlowWorkBuilder.java │ │ │ └── SchemaReader.java │ │ │ ├── content │ │ │ ├── FlowSession.java │ │ │ └── FlowSessionBeanProvider.java │ │ │ ├── domain │ │ │ ├── FlowButton.java │ │ │ ├── FlowNode.java │ │ │ ├── FlowRelation.java │ │ │ ├── FlowWork.java │ │ │ └── Opinion.java │ │ │ ├── em │ │ │ ├── ApprovalType.java │ │ │ ├── FlowButtonType.java │ │ │ ├── FlowSourceDirection.java │ │ │ ├── FlowStatus.java │ │ │ ├── FlowType.java │ │ │ └── NodeType.java │ │ │ ├── error │ │ │ ├── ErrTrigger.java │ │ │ ├── ErrorResult.java │ │ │ ├── NodeResult.java │ │ │ └── OperatorResult.java │ │ │ ├── event │ │ │ └── FlowApprovalEvent.java │ │ │ ├── generator │ │ │ └── TitleGenerator.java │ │ │ ├── matcher │ │ │ └── OperatorMatcher.java │ │ │ ├── pojo │ │ │ ├── FlowDetail.java │ │ │ ├── FlowResult.java │ │ │ ├── FlowStepResult.java │ │ │ └── FlowSubmitResult.java │ │ │ ├── query │ │ │ └── FlowRecordQuery.java │ │ │ ├── record │ │ │ ├── FlowBackup.java │ │ │ ├── FlowMerge.java │ │ │ ├── FlowProcess.java │ │ │ └── FlowRecord.java │ │ │ ├── repository │ │ │ ├── FlowBackupRepository.java │ │ │ ├── FlowBindDataRepository.java │ │ │ ├── FlowOperatorRepository.java │ │ │ ├── FlowProcessRepository.java │ │ │ ├── FlowRecordRepository.java │ │ │ └── FlowWorkRepository.java │ │ │ ├── result │ │ │ ├── MessageResult.java │ │ │ └── ResultState.java │ │ │ ├── script │ │ │ └── GroovyShellContext.java │ │ │ ├── serializable │ │ │ ├── FlowNodeSerializable.java │ │ │ ├── FlowRelationSerializable.java │ │ │ └── FlowWorkSerializable.java │ │ │ ├── service │ │ │ ├── FlowDirectionService.java │ │ │ ├── FlowNodeService.java │ │ │ ├── FlowRecordVerifyService.java │ │ │ ├── FlowService.java │ │ │ ├── FlowServiceRepositoryHolder.java │ │ │ └── impl │ │ │ │ ├── FlowBackService.java │ │ │ │ ├── FlowCustomEventService.java │ │ │ │ ├── FlowDetailService.java │ │ │ │ ├── FlowNotifyService.java │ │ │ │ ├── FlowPostponedService.java │ │ │ │ ├── FlowRecallService.java │ │ │ │ ├── FlowRemoveService.java │ │ │ │ ├── FlowSaveService.java │ │ │ │ ├── FlowStartService.java │ │ │ │ ├── FlowStepService.java │ │ │ │ ├── FlowSubmitService.java │ │ │ │ ├── FlowTransferService.java │ │ │ │ ├── FlowTrySubmitService.java │ │ │ │ ├── FlowUrgeService.java │ │ │ │ └── FlowVoidedService.java │ │ │ ├── trigger │ │ │ └── OutTrigger.java │ │ │ ├── user │ │ │ └── IFlowOperator.java │ │ │ └── utils │ │ │ └── Sha256Utils.java │ └── resources │ │ └── META-INF │ │ └── spring │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ └── test │ └── java │ └── com │ └── codingapi │ └── springboot │ └── flow │ ├── FlowTestApplication.java │ ├── flow │ ├── Leave.java │ └── Leave2.java │ ├── repository │ ├── FlowBackupRepositoryImpl.java │ ├── FlowBindDataRepositoryImpl.java │ ├── FlowProcessRepositoryImpl.java │ ├── FlowRecordRepositoryImpl.java │ ├── FlowWorkRepositoryImpl.java │ ├── LeaveRepository.java │ └── UserRepository.java │ ├── script │ └── GroovyShellContextTest.java │ ├── test │ ├── BuildTest.java │ ├── CirculateTest.java │ ├── ErrorTest.java │ ├── FlowBackTest.java │ ├── FlowMapTest.java │ ├── FlowTest.java │ ├── FlowTest2.java │ ├── FlowTest3.java │ ├── FlowVoidedTest.java │ ├── MultiRelationFlowTest.java │ ├── QueryTest.java │ ├── ScriptBuildTest.java │ ├── ScriptTest.java │ ├── SignTest.java │ └── TrySubmitTest.java │ └── user │ └── User.java ├── springboot-starter-security ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── codingapi │ │ │ └── springboot │ │ │ └── security │ │ │ ├── AutoConfiguration.java │ │ │ ├── configurer │ │ │ ├── HttpSecurityConfigurer.java │ │ │ └── WebSecurityConfigurer.java │ │ │ ├── controller │ │ │ └── VersionController.java │ │ │ ├── crypto │ │ │ ├── AESTools.java │ │ │ └── SecurityCryptoConfiguration.java │ │ │ ├── customer │ │ │ ├── DefaultHttpSecurityCustomer.java │ │ │ └── HttpSecurityCustomer.java │ │ │ ├── dto │ │ │ ├── request │ │ │ │ ├── LoginRequest.java │ │ │ │ └── LoginRequestContext.java │ │ │ └── response │ │ │ │ └── LoginResponse.java │ │ │ ├── exception │ │ │ └── TokenExpiredException.java │ │ │ ├── filter │ │ │ ├── AuthenticationTokenFilter.java │ │ │ ├── MyAccessDeniedHandler.java │ │ │ ├── MyAuthenticationFilter.java │ │ │ ├── MyLoginFilter.java │ │ │ ├── MyLogoutHandler.java │ │ │ ├── MyLogoutSuccessHandler.java │ │ │ ├── MyUnAuthenticationEntryPoint.java │ │ │ └── SecurityLoginHandler.java │ │ │ ├── gateway │ │ │ ├── Token.java │ │ │ ├── TokenContext.java │ │ │ └── TokenGateway.java │ │ │ ├── jwt │ │ │ ├── JWTSecurityConfiguration.java │ │ │ ├── JWTTokenGatewayImpl.java │ │ │ ├── JwtTokenGateway.java │ │ │ └── SecurityJWTProperties.java │ │ │ ├── properties │ │ │ └── CodingApiSecurityProperties.java │ │ │ └── redis │ │ │ ├── RedisSecurityConfiguration.java │ │ │ ├── RedisTokenGateway.java │ │ │ ├── RedisTokenGatewayImpl.java │ │ │ └── SecurityRedisProperties.java │ └── resources │ │ └── META-INF │ │ ├── spring.factories │ │ └── spring │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ └── test │ ├── java │ └── com │ │ └── codingapi │ │ └── springboot │ │ └── security │ │ ├── SecurityJwtApplication.java │ │ ├── SecurityJwtApplicationTest.java │ │ ├── controller │ │ └── DemoController.java │ │ └── jwt │ │ ├── TestVO.java │ │ └── TokenTest.java │ └── resources │ └── application.properties └── springboot-starter ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── codingapi │ │ └── springboot │ │ └── framework │ │ ├── AutoConfiguration.java │ │ ├── annotation │ │ ├── ColumnType.java │ │ ├── MetaColumn.java │ │ ├── MetaRelation.java │ │ └── MetaTable.java │ │ ├── boot │ │ └── DynamicApplication.java │ │ ├── command │ │ └── IExecutor.java │ │ ├── convert │ │ └── BeanConvertor.java │ │ ├── crypto │ │ ├── AES.java │ │ ├── AESUtils.java │ │ ├── DES.java │ │ ├── DESUtils.java │ │ ├── HmacSHA256.java │ │ ├── RSA.java │ │ └── RSAUtils.java │ │ ├── domain │ │ ├── IDomain.java │ │ ├── ISort.java │ │ ├── event │ │ │ ├── DomainChangeEvent.java │ │ │ ├── DomainCreateEvent.java │ │ │ ├── DomainDeleteEvent.java │ │ │ ├── DomainEvent.java │ │ │ └── DomainPersistEvent.java │ │ └── proxy │ │ │ ├── DomainChangeInterceptor.java │ │ │ └── DomainProxyFactory.java │ │ ├── dto │ │ ├── request │ │ │ ├── Filter.java │ │ │ ├── IdRequest.java │ │ │ ├── PageRequest.java │ │ │ ├── Relation.java │ │ │ ├── RequestFilter.java │ │ │ ├── SearchRequest.java │ │ │ └── SortRequest.java │ │ └── response │ │ │ ├── MapResponse.java │ │ │ ├── MultiResponse.java │ │ │ ├── Response.java │ │ │ └── SingleResponse.java │ │ ├── em │ │ └── IEnum.java │ │ ├── event │ │ ├── ApplicationHandlerUtils.java │ │ ├── DomainEvent.java │ │ ├── DomainEventContext.java │ │ ├── EventPusher.java │ │ ├── EventStackContext.java │ │ ├── EventTraceContext.java │ │ ├── Handler.java │ │ ├── HandlerBeanDefinitionRegistrar.java │ │ ├── IAsyncEvent.java │ │ ├── IEvent.java │ │ ├── IHandler.java │ │ ├── ISyncEvent.java │ │ ├── SpringEventConfiguration.java │ │ ├── SpringEventHandler.java │ │ ├── SpringEventInitializer.java │ │ └── SpringHandlerConfiguration.java │ │ ├── exception │ │ ├── EventException.java │ │ ├── EventLoopException.java │ │ ├── ExceptionConfiguration.java │ │ ├── LocaleMessage.java │ │ ├── LocaleMessageException.java │ │ └── MessageContext.java │ │ ├── math │ │ └── Arithmetic.java │ │ ├── registrar │ │ └── RegisterBeanScanner.java │ │ ├── rest │ │ ├── HttpClient.java │ │ ├── HttpRequest.java │ │ ├── Request.java │ │ ├── RestClient.java │ │ ├── RestTemplateContext.java │ │ ├── SessionClient.java │ │ ├── param │ │ │ ├── IRestParam.java │ │ │ └── RestParam.java │ │ └── properties │ │ │ └── HttpProxyProperties.java │ │ ├── serializable │ │ ├── EnumSerializer.java │ │ ├── JsonSerializable.java │ │ └── MapSerializable.java │ │ ├── servlet │ │ └── BasicHandlerExceptionResolverConfiguration.java │ │ ├── trigger │ │ ├── Trigger.java │ │ ├── TriggerContext.java │ │ └── TriggerHandler.java │ │ └── utils │ │ ├── ClassLoaderUtils.java │ │ ├── FullDateFormatUtils.java │ │ ├── RandomGenerator.java │ │ └── TrustAnyHttpClientFactory.java └── resources │ ├── META-INF │ ├── spring.factories │ └── spring │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ └── banner.txt └── test ├── java └── com │ └── codingapi │ └── springboot │ └── framework │ ├── FrameWorkApplication.java │ ├── FrameworkApplicationTests.java │ ├── controller │ └── DemoController.java │ ├── crypto │ ├── AESTest.java │ ├── AESUtilsTest.java │ ├── DESTest.java │ ├── DESUtilsTest.java │ ├── HmacSHA256Test.java │ ├── RSATest.java │ └── RSAUtilsTest.java │ ├── domain │ ├── Animal.java │ ├── Demo.java │ ├── DemoEntity.java │ ├── DemoTest.java │ └── DomainProxyFactoryTest.java │ ├── dto │ ├── ResponseTest.java │ └── request │ │ ├── PageRequestTest.java │ │ └── SearchRequestTest.java │ ├── event │ ├── DemoChangeEvent.java │ └── EventPusherTest.java │ ├── exception │ └── LocaleMessageExceptionTest.java │ ├── handler │ ├── DemoChangeLogHandler.java │ ├── DemoCreateHandler.java │ ├── DemoDeleteHandler.java │ ├── DemoPersistEventHandler.java │ └── EntityFiledChangeHandler.java │ ├── math │ └── ArithmeticTest.java │ ├── query │ ├── entity │ │ └── Demo.java │ ├── repository │ │ └── DemoRepository.java │ └── test │ │ └── DemoRepositoryTest.java │ ├── rest │ ├── RestClientTest.java │ └── SessionClientTest.java │ ├── trigger │ └── TriggerHandlerContextTest.java │ └── utils │ ├── FullDateFormatUtilsTest.java │ └── TrustAnyHttpClientFactoryTest.java └── resources ├── application.properties └── messages.properties /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 16 | 1. Go to '...' 17 | 2. Click on '....' 18 | 3. Scroll down to '....' 19 | 4. See error 20 | 21 | **Expected behavior** 22 | A clear and concise description of what you expected to happen. 23 | 24 | **Screenshots** 25 | If applicable, add screenshots to help explain your problem. 26 | 27 | **Desktop (please complete the following information):** 28 | 29 | - OS: [e.g. iOS] 30 | - Browser [e.g. chrome, safari] 31 | - Version [e.g. 22] 32 | 33 | **Smartphone (please complete the following information):** 34 | 35 | - Device: [e.g. iPhone6] 36 | - OS: [e.g. iOS8.1] 37 | - Browser [e.g. stock browser, safari] 38 | - Version [e.g. 22] 39 | 40 | **Additional context** 41 | Add any other context about the problem here. 42 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | ### Describe what this PR does / why we need it 7 | 8 | ### Does this pull request fix one issue? 9 | 10 | 11 | 12 | ### Describe how you did it 13 | 14 | ### Describe how to verify it 15 | 16 | ### Special notes for reviews 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | *.db 35 | *.trace.db 36 | 37 | ### jars ### 38 | /jars/ 39 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingapi/springboot-framework/79e75cf02383c413eec0ae8c798f7302e0de543e/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.2/apache-maven-3.8.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | jdk: openjdk20 4 | 5 | branches: 6 | only: 7 | - main 8 | - dev 9 | 10 | before_install: 11 | - pip install --user codecov 12 | 13 | script: 14 | - mvn clean test -P travis 15 | 16 | after_success: 17 | - bash <(curl -s https://codecov.io/bash) 18 | 19 | env: 20 | global: 21 | - CODECOV_TOKEN=eb1a776c-6802-4c65-90cd-6a8a2791e2f4 22 | -------------------------------------------------------------------------------- /admin-ui/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | /.idea 4 | 5 | # dependencies 6 | /node_modules 7 | /.pnp 8 | .pnp.js 9 | 10 | # testing 11 | /coverage 12 | 13 | # production 14 | /build 15 | /dist 16 | 17 | # misc 18 | .DS_Store 19 | .env.local 20 | .env.development.local 21 | .env.test.local 22 | .env.production.local 23 | 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | yarn.lock 28 | package-lock.json 29 | -------------------------------------------------------------------------------- /admin-ui/README.md: -------------------------------------------------------------------------------- 1 | # Admin-ui with Antd For Micro Frontends 2 | 3 | This is a simple React App with Webpack5 & Typescript. 4 | 5 | ## Features 6 | 1. Support Webpack 5 ModuleFederationPlugin for Micro Frontends 7 | 2. Support Dynamic zip component loading 8 | 3. Support Dynamic Routing & Dynamic Menu 9 | 4. Support Axios for API calls 10 | 5. Support Antd & Pro-Components UI Library 11 | 6. Support Redux for State Management 12 | 7. Support Mock Server for API Mocking 13 | 8. Support Monaco Editor for Code Editor 14 | 9. Support Access ControlPanel for Menu & Page Components 15 | 10. Support Jest for Unit Testing 16 | 11. Support DockerCompose for Deployment 17 | 18 | ## Running 19 | ```shell 20 | yarn 21 | 22 | yarn start 23 | ``` 24 | ## Build 25 | ```shell 26 | yarn build 27 | ``` 28 | 29 | ## Deploy 30 | ```shell 31 | cd scripts 32 | sh package.sh 33 | sh deploy.sh 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /admin-ui/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'jsdom', 4 | moduleNameMapper: { 5 | '\\.(css|less|scss|sass)$': 'identity-obj-proxy', 6 | }, 7 | setupFilesAfterEnv: ['/jest.setup.ts'], 8 | }; -------------------------------------------------------------------------------- /admin-ui/jest.setup.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | 3 | Object.defineProperty(window, 'matchMedia', { 4 | writable: true, 5 | value: jest.fn().mockImplementation(query => ({ 6 | matches: false, 7 | media: query, 8 | onchange: null, 9 | addListener: jest.fn(), // 旧版 API 10 | removeListener: jest.fn(), // 旧版 API 11 | addEventListener: jest.fn(), // 新版 API 12 | removeEventListener: jest.fn(), // 新版 API 13 | dispatchEvent: jest.fn(), 14 | })), 15 | }); -------------------------------------------------------------------------------- /admin-ui/jest/map.test.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | 3 | 4 | test("map", () => { 5 | const map = new Map(); 6 | map.set('key', 'value'); 7 | expect(map.get('key')).toBe('value'); 8 | expect(map.has('key')).toBe(true); 9 | expect(map.size).toBe(1); 10 | map.delete('key'); 11 | expect(map.has('key')).toBe(false); 12 | expect(map.size).toBe(0); 13 | }) -------------------------------------------------------------------------------- /admin-ui/mocks/product.ts: -------------------------------------------------------------------------------- 1 | import Mock from "mockjs"; 2 | import webpackMockServer from "webpack-mock-server"; 3 | 4 | export default webpackMockServer.add((app, helper) => { 5 | app.get('/api/products', (req, res) => { 6 | const products = Mock.mock({ 7 | 'list|100': [{ 8 | 'id|+1': 1, 9 | 'name': '@name', 10 | 'price|100-1000': 1, 11 | }] 12 | }).list; 13 | 14 | res.json({ 15 | success: true, 16 | data:{ 17 | list:products, 18 | total: products.length 19 | }, 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /admin-ui/mocks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": [ 4 | "../mocks/*", 5 | "*.mock.ts", 6 | "**/global.d.ts" 7 | ], 8 | "files": [], 9 | "exclude": [ 10 | "*test.mock.ts" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /admin-ui/mocks/user.ts: -------------------------------------------------------------------------------- 1 | import webpackMockServer from "webpack-mock-server"; 2 | 3 | export default webpackMockServer.add((app, helper) => { 4 | app.post('/user/login', (req, res) => { 5 | const username = req.body.username; 6 | if(username==='admin'){ 7 | res.json({ 8 | success:true, 9 | data:{ 10 | 'username': username, 11 | 'token':'test token', 12 | 'avatar':'/logo.png', 13 | 'authorities': ['ROLE_ADMIN','ROLE_DEVELOPER'], 14 | } 15 | }); 16 | return; 17 | } 18 | 19 | res.json({ 20 | success:true, 21 | data:{ 22 | 'username': username, 23 | 'token':'test token', 24 | 'avatar':'/logo.png', 25 | 'authorities': ['ROLE_USER'], 26 | } 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /admin-ui/public/captcha.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingapi/springboot-framework/79e75cf02383c413eec0ae8c798f7302e0de543e/admin-ui/public/captcha.jpeg -------------------------------------------------------------------------------- /admin-ui/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingapi/springboot-framework/79e75cf02383c413eec0ae8c798f7302e0de543e/admin-ui/public/favicon.ico -------------------------------------------------------------------------------- /admin-ui/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingapi/springboot-framework/79e75cf02383c413eec0ae8c798f7302e0de543e/admin-ui/public/logo.png -------------------------------------------------------------------------------- /admin-ui/scripts/.gitignore: -------------------------------------------------------------------------------- 1 | /admin 2 | -------------------------------------------------------------------------------- /admin-ui/scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | serverHost=server 2 | serverAccount=root 3 | serverPort=22 4 | serverPath=/opt/test/ 5 | 6 | 7 | scp -o ConnectTimeout=30 -P $serverPort -r * $serverAccount@$serverHost:$serverPath 8 | ssh -p $serverPort $serverAccount@$serverHost "cd $serverPath && sed -i 's/\r//g' *.sh && sh install.sh" 9 | -------------------------------------------------------------------------------- /admin-ui/scripts/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | admin-nginx: 5 | image: nginx:latest 6 | volumes: 7 | - "./admin:/usr/share/nginx/html" 8 | environment: 9 | TZ: "Asia/Shanghai" 10 | restart: always 11 | ports: 12 | - "13000:80" -------------------------------------------------------------------------------- /admin-ui/scripts/install.sh: -------------------------------------------------------------------------------- 1 | docker-compose build --no-cache 2 | docker-compose up -d 3 | docker ps -a -------------------------------------------------------------------------------- /admin-ui/scripts/package.sh: -------------------------------------------------------------------------------- 1 | rm -rf admin 2 | 3 | cd .. 4 | yarn 5 | yarn run build 6 | 7 | 8 | cp -r ./dist/ ./scripts/admin/ -------------------------------------------------------------------------------- /admin-ui/src/api/account.ts: -------------------------------------------------------------------------------- 1 | import {httpClient} from "@/api/index"; 2 | 3 | export async function login(body: Account.LoginRequest) { 4 | return httpClient.post('/user/login', body); 5 | } 6 | 7 | export async function captcha() { 8 | return httpClient.get('/open/captcha'); 9 | } 10 | 11 | 12 | export function clearUser() { 13 | localStorage.removeItem('username'); 14 | localStorage.removeItem('token'); 15 | localStorage.removeItem('authorities'); 16 | localStorage.removeItem('avatar'); 17 | } 18 | 19 | export function initUser(user: { 20 | username: string; 21 | token: string; 22 | authorities: string[]; 23 | avatar: string; 24 | }) { 25 | const {username, token, authorities, avatar} = user; 26 | localStorage.setItem('username', username); 27 | localStorage.setItem('token', token); 28 | if(authorities) { 29 | localStorage.setItem('authorities', JSON.stringify(authorities)); 30 | } 31 | localStorage.setItem('avatar', avatar || "/logo.png"); 32 | } 33 | -------------------------------------------------------------------------------- /admin-ui/src/api/index.ts: -------------------------------------------------------------------------------- 1 | import {message} from "antd"; 2 | import {HttpClient} from "@codingapi/ui-framework"; 3 | 4 | export const httpClient = new HttpClient(10000, { 5 | success:(msg:string)=>{ 6 | message.success(msg).then(); 7 | }, 8 | error:(msg:string)=>{ 9 | message.error(msg).then(); 10 | } 11 | }) 12 | -------------------------------------------------------------------------------- /admin-ui/src/api/jar.ts: -------------------------------------------------------------------------------- 1 | import {httpClient} from "@/api/index"; 2 | 3 | export async function upload(body: any) { 4 | return httpClient.post('/api/jar/upload', body); 5 | } 6 | 7 | export async function restart() { 8 | return httpClient.post('/api/jar/restart',{}); 9 | } 10 | -------------------------------------------------------------------------------- /admin-ui/src/api/leave.ts: -------------------------------------------------------------------------------- 1 | import {httpClient} from "@/api/index"; 2 | 3 | export async function list( 4 | params: any, 5 | sort: any, 6 | filter: any, 7 | match: { 8 | key: string, 9 | type: string 10 | }[] 11 | ) { 12 | return httpClient.page('/api/query/leave/list', params, sort, filter, match); 13 | } 14 | 15 | 16 | 17 | export async function startLeave(body: any) { 18 | return httpClient.post('/api/cmd/leave/startLeave', body); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /admin-ui/src/api/oss.ts: -------------------------------------------------------------------------------- 1 | import {httpClient} from "@/api/index"; 2 | 3 | 4 | export async function loadFiles(ids: string) { 5 | return httpClient.get('/api/oss/load', {ids: ids}); 6 | } 7 | 8 | 9 | export async function upload(body: any) { 10 | return httpClient.post('/api/oss/upload', body); 11 | } 12 | -------------------------------------------------------------------------------- /admin-ui/src/api/product.ts: -------------------------------------------------------------------------------- 1 | import {httpClient} from "@/api/index"; 2 | 3 | 4 | export async function products() { 5 | return httpClient.get('/api/products'); 6 | } 7 | 8 | -------------------------------------------------------------------------------- /admin-ui/src/api/typings.d.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | /* eslint-disable */ 3 | 4 | declare namespace API { 5 | type CurrentUser = { 6 | username?: string; 7 | authorities?: string[]; 8 | avatar?: string; 9 | }; 10 | 11 | type Response = { 12 | status: string; 13 | success: boolean; 14 | errCode: string; 15 | errMessage: string; 16 | data: T; 17 | } 18 | 19 | } 20 | 21 | 22 | declare namespace Account { 23 | 24 | type LoginResponse = { 25 | token: string; 26 | username: string; 27 | authorities: string[]; 28 | }; 29 | 30 | 31 | type LoginRequest = { 32 | username?: string; 33 | password?: string; 34 | type?: string; 35 | }; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /admin-ui/src/components/icons/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Icon, * as icons from '@ant-design/icons' 3 | 4 | interface MenuIconProps { 5 | icon: string 6 | className?: string; 7 | style?: React.CSSProperties; 8 | onClick?: () => void; 9 | } 10 | 11 | const Icons: React.FC = (props) => { 12 | if (props.icon === '-') { 13 | return <> 14 | } 15 | 16 | // @ts-ignore 17 | const component = icons[props.icon]; 18 | if (props.icon) { 19 | return ( 20 | 26 | ) 27 | } else { 28 | return <> 29 | } 30 | } 31 | export default Icons; 32 | -------------------------------------------------------------------------------- /admin-ui/src/config/register.component.tsx: -------------------------------------------------------------------------------- 1 | import "@/components/flow/register"; 2 | -------------------------------------------------------------------------------- /admin-ui/src/config/theme.tsx: -------------------------------------------------------------------------------- 1 | 2 | export const config = { 3 | // 后台名称 4 | title: 'Admin UI', 5 | // 后台logo 6 | logo: '/logo.png', 7 | // 欢迎页路径 8 | welcomePath: '/welcome', 9 | // 登录页路径 10 | loginPath: '/login', 11 | // 侧边栏宽度 12 | siderWidth: 216, 13 | // 侧边栏布局 14 | layout: 'mix' as 'side' | 'top' | 'mix', 15 | // 水印 16 | waterMark: 'default waterMark', 17 | } 18 | 19 | -------------------------------------------------------------------------------- /admin-ui/src/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' { 2 | const content: any; 3 | export default content; 4 | } -------------------------------------------------------------------------------- /admin-ui/src/framework/DynamicLoad/PageLoader.tsx: -------------------------------------------------------------------------------- 1 | import React, {lazy, Suspense} from 'react'; 2 | import {Spin} from "antd"; 3 | 4 | export const loadPage = (pageName: string) => { 5 | 6 | const PageComponent = lazy(() => { 7 | return import(`@/pages/${pageName}`); 8 | }); 9 | 10 | const fallback = ( 11 | 12 |
13 | 14 | ); 15 | 16 | return ( 17 | 18 | 19 | 20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /admin-ui/src/framework/Permission/RoleKeyProvider/RoleKeyManager.ts: -------------------------------------------------------------------------------- 1 | interface RoleKey { 2 | key: string; 3 | children?: RoleKey[]; 4 | } 5 | 6 | class RoleKeyManager { 7 | private roles: RoleKey[] = []; 8 | 9 | private static manager = new RoleKeyManager(); 10 | 11 | static getInstances(): RoleKeyManager { 12 | return RoleKeyManager.manager; 13 | } 14 | 15 | addRole(role: RoleKey): void { 16 | this.roles.push(role); 17 | } 18 | 19 | public hasRole(code: string) { 20 | return this.roles.some((role: RoleKey) => { 21 | return role.key === code; 22 | }) 23 | } 24 | } 25 | 26 | export default RoleKeyManager; -------------------------------------------------------------------------------- /admin-ui/src/gateway/default/Header.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import {HeaderProps} from "@/gateway"; 3 | 4 | 5 | const HeaderDefault: React.FC = (props) => { 6 | return ( 7 |
8 |

{props.title}

9 | 10 |
11 | PS:local default component 12 |
13 |
14 | ) 15 | } 16 | 17 | export default HeaderDefault; 18 | -------------------------------------------------------------------------------- /admin-ui/src/gateway/index.tsx: -------------------------------------------------------------------------------- 1 | 2 | export interface HeaderProps{ 3 | title: string; 4 | onClick: () => void; 5 | } 6 | 7 | -------------------------------------------------------------------------------- /admin-ui/src/layout/HeaderAction/index.tsx: -------------------------------------------------------------------------------- 1 | export const loadHeaderAction = (props: any) => { 2 | if (props.isMobile) return []; 3 | return [ 4 | ]; 5 | } 6 | 7 | -------------------------------------------------------------------------------- /admin-ui/src/layout/HeaderDropdown/index.tsx: -------------------------------------------------------------------------------- 1 | import { Dropdown } from 'antd'; 2 | import type { DropDownProps } from 'antd/es/dropdown'; 3 | import React from 'react'; 4 | 5 | export type HeaderDropdownProps = { 6 | overlayClassName?: string; 7 | placement?: 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topCenter' | 'topRight' | 'bottomCenter'; 8 | } & Omit; 9 | 10 | const HeaderDropdown: React.FC = ({ overlayClassName: cls, ...restProps }) => { 11 | 12 | return ; 13 | }; 14 | 15 | export default HeaderDropdown; 16 | -------------------------------------------------------------------------------- /admin-ui/src/layout/NotFound/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import {Button, Result} from "antd"; 3 | import {useNavigate} from "react-router"; 4 | import {config} from "@/config/theme"; 5 | import {useDispatch} from "react-redux"; 6 | import {refresh} from "@/store/MenuSlice"; 7 | 8 | const Index = () => { 9 | const navigate = useNavigate(); 10 | const dispatch = useDispatch(); 11 | 12 | const goHome = () => { 13 | navigate(config.welcomePath, {replace: true}); 14 | dispatch(refresh()); 15 | } 16 | 17 | return ( 18 | 27 | Back Home 28 | 29 | )} 30 | /> 31 | ) 32 | } 33 | 34 | export default Index; 35 | -------------------------------------------------------------------------------- /admin-ui/src/layout/index.scss: -------------------------------------------------------------------------------- 1 | .breadcrumb-item { 2 | color: #b88888; 3 | } -------------------------------------------------------------------------------- /admin-ui/src/pages/flow/record/index.scss: -------------------------------------------------------------------------------- 1 | .record-read{ 2 | font-weight: normal; 3 | } 4 | 5 | .record-unread{ 6 | font-weight: bold; 7 | } 8 | -------------------------------------------------------------------------------- /admin-ui/src/pages/welcome/index.scss: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | min-height: 100vh; 18 | display: flex; 19 | flex-direction: column; 20 | align-items: center; 21 | justify-content: center; 22 | font-size: calc(10px + 2vmin); 23 | } 24 | 25 | .App-link { 26 | } 27 | 28 | @keyframes App-logo-spin { 29 | from { 30 | transform: rotate(0deg); 31 | } 32 | to { 33 | transform: rotate(360deg); 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /admin-ui/src/pages/welcome/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {PageContainer} from "@ant-design/pro-components"; 3 | import './index.scss'; 4 | 5 | 6 | const WelcomePage = () => { 7 | 8 | return ( 9 | 10 | 11 |
    Admin-UI 支持的功能有
12 |
    1. 自定义流程
13 |
    2. 表单渲染
14 |
    3. 管理权限
15 |
    4. 动态菜单
16 |
    5. 动态加载组件
17 |
18 | ); 19 | } 20 | 21 | export default WelcomePage; 22 | -------------------------------------------------------------------------------- /admin-ui/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /admin-ui/src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /admin-ui/src/store/CounterSlice.ts: -------------------------------------------------------------------------------- 1 | import {createSlice} from '@reduxjs/toolkit'; 2 | 3 | export interface CounterStore { 4 | value: number; 5 | } 6 | 7 | export type CounterStoreAction = { 8 | increment: (state: CounterStore) => void; 9 | decrement: (state: CounterStore) => void; 10 | clear: (state: CounterStore) => void; 11 | } 12 | 13 | export const counterSlice = createSlice({ 14 | name: 'counter', 15 | initialState: { 16 | value: 0, 17 | }, 18 | reducers: { 19 | increment: (state) => { 20 | state.value += 1; 21 | }, 22 | decrement: (state) => { 23 | state.value -= 1; 24 | }, 25 | clear: (state) => { 26 | state.value = 0; 27 | }, 28 | }, 29 | }); 30 | 31 | export const {increment, decrement, clear} = counterSlice.actions; 32 | 33 | -------------------------------------------------------------------------------- /admin-ui/src/store/MenuSlice.ts: -------------------------------------------------------------------------------- 1 | import {createSlice} from '@reduxjs/toolkit'; 2 | 3 | export interface MenuStore { 4 | version: number; 5 | } 6 | 7 | export type MenuStoreAction = { 8 | refresh: (state: MenuStore) => void; 9 | } 10 | 11 | export const menuSlice = createSlice({ 12 | name: 'menu', 13 | initialState: { 14 | version: 0, 15 | }, 16 | reducers: { 17 | refresh: (state) => { 18 | state.version = Math.random(); 19 | }, 20 | }, 21 | }); 22 | 23 | export const {refresh} = menuSlice.actions; 24 | 25 | -------------------------------------------------------------------------------- /admin-ui/src/store/Redux.tsx: -------------------------------------------------------------------------------- 1 | import {configureStore} from '@reduxjs/toolkit'; 2 | import {counterSlice} from './CounterSlice'; 3 | import {menuSlice} from './MenuSlice'; 4 | 5 | const store = configureStore({ 6 | reducer: { 7 | counter: counterSlice.reducer, 8 | menu: menuSlice.reducer, 9 | }, 10 | }); 11 | 12 | export type RootState = ReturnType; 13 | export default store; -------------------------------------------------------------------------------- /admin-ui/src/styles/index.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --primary-color: #094edc; 3 | --body-background-color: #fdfdfd; 4 | 5 | --content-font-size-large: 24px; 6 | --content-font-size-middle: 16px; 7 | --content-font-size-small: 12px; 8 | 9 | --content-font-size: var(--content-font-size-middle); 10 | } 11 | 12 | 13 | body { 14 | margin: 0; 15 | padding: 0; 16 | -webkit-font-smoothing: antialiased; 17 | -moz-osx-font-smoothing: grayscale; 18 | background-color: var(--body-background-color); 19 | font-size: var(--content-font-size); 20 | } 21 | 22 | code { 23 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 24 | monospace; 25 | } 26 | -------------------------------------------------------------------------------- /admin-ui/src/styles/mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin flex-center { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | width: 100%; 6 | } 7 | 8 | @mixin flex-right { 9 | display: flex; 10 | justify-content: right; 11 | align-items: center; 12 | width: 100%; 13 | } -------------------------------------------------------------------------------- /admin-ui/src/styles/variable.scss: -------------------------------------------------------------------------------- 1 | // 主题颜色 2 | $theme-primary-color: var(--primary-color, #4a79d8); 3 | // 背景颜色 4 | $body-background-color: var(--body-background-color, #fdfdfd); 5 | 6 | // 标题字体大小 7 | $title-font-size: var(--content-font-size-middle, 16px); 8 | // 内容字体大小 9 | $content-font-size:var(--content-font-size, 12px); 10 | -------------------------------------------------------------------------------- /admin-ui/src/utils/captcha.ts: -------------------------------------------------------------------------------- 1 | import {captcha} from "@/api/account"; 2 | 3 | class CaptchaUtils { 4 | 5 | static refresh = async () => { 6 | const res = await captcha(); 7 | if (res.success) { 8 | return { 9 | url: res.data.captcha, 10 | code: res.data.key 11 | } 12 | } 13 | return null; 14 | } 15 | } 16 | 17 | export default CaptchaUtils; 18 | -------------------------------------------------------------------------------- /admin-ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": false, 21 | "jsx": "react-jsx", 22 | "baseUrl": ".", 23 | "paths": { 24 | "@/*": ["src/*"] 25 | } 26 | }, 27 | "include": [ 28 | "src" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /admin-ui/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | const {merge} = require('webpack-merge'); 2 | const common = require('./webpack.common.js'); 3 | 4 | module.exports = merge(common, { 5 | mode: 'development', 6 | devServer: { 7 | port: 8000, 8 | 9 | proxy: [ 10 | { 11 | context: ['/api','/open','/user'], 12 | target: 'http://127.0.0.1:8090', 13 | changeOrigin: true, 14 | logLevel: 'debug', 15 | onProxyReq: (proxyReq, req, res) => { 16 | console.log('Proxying request:', req.url); 17 | }, 18 | } 19 | ] 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /admin-ui/webpack.config.mock.js: -------------------------------------------------------------------------------- 1 | const {merge} = require('webpack-merge'); 2 | const common = require('./webpack.common.js'); 3 | const webpackMockServer = require('webpack-mock-server'); 4 | 5 | module.exports = merge(common, { 6 | mode: 'development', 7 | devServer: { 8 | port: 8000, 9 | 10 | setupMiddlewares: (middlewares, devServer) => { 11 | if (!devServer) { 12 | throw new Error('webpack-dev-server is not defined'); 13 | } 14 | 15 | // 使用 webpackMockServer 来添加 mock 功能 16 | webpackMockServer.use(devServer.app,{ 17 | port: 8090, 18 | entry:[ 19 | './mocks/user.ts', 20 | './mocks/product.ts', 21 | ], 22 | tsConfigFileName: "mocks/tsconfig.json" 23 | }); 24 | 25 | console.log('mock server is running'); 26 | return middlewares; // 返回 middlewares 27 | } 28 | }, 29 | }); 30 | -------------------------------------------------------------------------------- /admin-ui/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | const {merge} = require('webpack-merge'); 2 | const common = require('./webpack.common.js'); 3 | 4 | module.exports = merge(common,{ 5 | mode: 'production', 6 | devServer: { 7 | port: 8000, 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | patch: 4 | default: 5 | threshold: 0.60% 6 | ignore: 7 | - ".mvn/.*" 8 | - "sql/.*" 9 | -------------------------------------------------------------------------------- /docs/img/ddd_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingapi/springboot-framework/79e75cf02383c413eec0ae8c798f7302e0de543e/docs/img/ddd_architecture.png -------------------------------------------------------------------------------- /event.md: -------------------------------------------------------------------------------- 1 | # 流程事件触发机制 2 | 3 | * 发起流程 4 | 事件: CREATE TODO SAVE 5 | * 保存流程 6 | 事件: SAVE 7 | * 提交流程 8 | 事件: PASS TODO(下一个节点记录数据) 9 | * 驳回流程 10 | 事件: REJECT TODO(下一个节点记录数据) 11 | * 撤回流程 12 | 事件: RECALL 13 | * 删除流程 14 | 事件: DELETE 15 | * 作废流程 16 | 事件: VOIDED 17 | * 退回流程 18 | 事件:BACK 19 | * 流程结束 20 | 事件: FINISH 21 | * 转办流程 22 | 事件:TRANSFER TODO(下一个节点记录数据) 23 | * 唤醒流程 24 | 事件: TODO 25 | * 催办流程 26 | 事件: URGE 当前审批人 27 | * 延期流程 28 | 事件: 未发送事件 29 | 30 | --------------------- 31 | 自定义事件:是前端自己触法的逻辑 32 | 自定义接口:是执行后端按钮配置的脚本 33 | 34 | 在开始节点点击任何按钮的时候,若流程不存在则会先执行流程的创建,然后再执行对应的按钮操作。 35 | 36 | 37 | -------------------------------------------------------------------------------- /example/example-app/example-app-cmd-domain/src/main/java/com/codingapi/example/app/cmd/domain/configuration/LeaveDomainConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.app.cmd.domain.configuration; 2 | 3 | import com.codingapi.example.domain.leave.repository.LeaveRepository; 4 | import com.codingapi.example.domain.leave.service.LeaveService; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | public class LeaveDomainConfiguration { 10 | 11 | @Bean 12 | public LeaveService leaveService(LeaveRepository leaveRepository){ 13 | return new LeaveService(leaveRepository); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/example-app/example-app-cmd-domain/src/main/java/com/codingapi/example/app/cmd/domain/configuration/UserDomainConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.app.cmd.domain.configuration; 2 | 3 | import com.codingapi.example.domain.user.gateway.PasswordEncoder; 4 | import com.codingapi.example.domain.user.repository.UserRepository; 5 | import com.codingapi.example.domain.user.service.UserService; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | public class UserDomainConfiguration { 11 | 12 | @Bean 13 | public UserService userService(UserRepository userRepository, PasswordEncoder passwordEncoder) { 14 | return new UserService(userRepository, passwordEncoder); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /example/example-app/example-app-cmd-domain/src/main/java/com/codingapi/example/app/cmd/domain/pojo/UserCmd.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.app.cmd.domain.pojo; 2 | 3 | import com.codingapi.example.domain.user.entity.UserMetric; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | public class UserCmd { 8 | 9 | @Setter 10 | @Getter 11 | public static class UpdateRequest{ 12 | private long id; 13 | private String name; 14 | private String username; 15 | private String password; 16 | 17 | public UserMetric toMetric(){ 18 | return new UserMetric(name, username, password); 19 | } 20 | 21 | private boolean flowManager; 22 | 23 | public boolean hasId(){ 24 | return id > 0; 25 | } 26 | } 27 | 28 | 29 | @Setter 30 | @Getter 31 | public static class EntrustRequest{ 32 | private long id; 33 | private long entrustUserId; 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /example/example-app/example-app-query/src/main/java/com/codingapi/example/app/query/service/FlowWorkQueryService.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.app.query.service; 2 | 3 | import com.codingapi.example.infra.flow.entity.FlowWorkEntity; 4 | import com.codingapi.example.infra.flow.jpa.FlowWorkEntityRepository; 5 | import com.codingapi.springboot.framework.dto.request.SearchRequest; 6 | import lombok.AllArgsConstructor; 7 | import org.springframework.data.domain.Page; 8 | import org.springframework.stereotype.Service; 9 | 10 | @Service 11 | @AllArgsConstructor 12 | public class FlowWorkQueryService { 13 | 14 | private final FlowWorkEntityRepository flowWorkEntityRepository; 15 | 16 | public Page list(SearchRequest searchRequest) { 17 | return flowWorkEntityRepository.searchRequest(searchRequest); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /example/example-app/example-app-query/src/main/java/com/codingapi/example/app/query/service/LeaveQueryService.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.app.query.service; 2 | 3 | 4 | import com.codingapi.example.infra.db.entity.LeaveEntity; 5 | import com.codingapi.example.infra.db.jpa.LeaveEntityRepository; 6 | import com.codingapi.springboot.framework.dto.request.SearchRequest; 7 | import lombok.AllArgsConstructor; 8 | import org.springframework.data.domain.Page; 9 | import org.springframework.stereotype.Service; 10 | 11 | @Service 12 | @AllArgsConstructor 13 | public class LeaveQueryService { 14 | 15 | private final LeaveEntityRepository leaveEntityRepository; 16 | 17 | public Page list(SearchRequest searchRequest){ 18 | return leaveEntityRepository.searchRequest(searchRequest); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /example/example-app/example-app-query/src/main/java/com/codingapi/example/app/query/service/UserQueryService.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.app.query.service; 2 | 3 | import com.codingapi.example.infra.db.entity.UserEntity; 4 | import com.codingapi.example.infra.db.jpa.UserEntityRepository; 5 | import com.codingapi.springboot.framework.dto.request.SearchRequest; 6 | import lombok.AllArgsConstructor; 7 | import org.springframework.data.domain.Page; 8 | import org.springframework.stereotype.Service; 9 | 10 | @Service 11 | @AllArgsConstructor 12 | public class UserQueryService { 13 | 14 | private final UserEntityRepository userEntityRepository; 15 | 16 | public Page list(SearchRequest searchRequest) { 17 | return userEntityRepository.searchRequest(searchRequest); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /example/example-app/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.codingapi.springboot 8 | springboot-example 9 | 3.4.8 10 | ../pom.xml 11 | 12 | pom 13 | example-app 14 | 15 | 16 | example-app-cmd-domain 17 | example-app-cmd-meta 18 | example-app-query 19 | 20 | 21 | 22 | UTF-8 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/example-domain/example-domain-leave/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.codingapi.springboot 8 | example-domain 9 | 3.4.8 10 | ../pom.xml 11 | 12 | 13 | example-domain-leave 14 | 15 | 16 | UTF-8 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /example/example-domain/example-domain-leave/src/main/java/com/codingapi/example/domain/leave/entity/Leave.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.domain.leave.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Setter 7 | @Getter 8 | public class Leave { 9 | 10 | private long id; 11 | private String desc; 12 | private int days; 13 | private String username; 14 | private long createTime; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /example/example-domain/example-domain-leave/src/main/java/com/codingapi/example/domain/leave/repository/LeaveRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.domain.leave.repository; 2 | 3 | 4 | import com.codingapi.example.domain.leave.entity.Leave; 5 | 6 | public interface LeaveRepository { 7 | 8 | void save(Leave leave); 9 | 10 | Leave getLeaveById(long id); 11 | 12 | 13 | } 14 | -------------------------------------------------------------------------------- /example/example-domain/example-domain-leave/src/main/java/com/codingapi/example/domain/leave/service/LeaveService.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.domain.leave.service; 2 | 3 | import com.codingapi.example.domain.leave.entity.Leave; 4 | import com.codingapi.example.domain.leave.repository.LeaveRepository; 5 | import lombok.AllArgsConstructor; 6 | 7 | @AllArgsConstructor 8 | public class LeaveService { 9 | 10 | private final LeaveRepository leaveRepository; 11 | 12 | public void create(Leave leave) { 13 | leaveRepository.save(leave); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/example-domain/example-domain-user/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.codingapi.springboot 8 | example-domain 9 | 3.4.8 10 | ../pom.xml 11 | 12 | 13 | example-domain-user 14 | 15 | 16 | UTF-8 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /example/example-domain/example-domain-user/src/main/java/com/codingapi/example/domain/user/entity/UserMetric.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.domain.user.entity; 2 | 3 | import com.codingapi.example.domain.user.gateway.PasswordEncoder; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | 8 | @Setter 9 | @Getter 10 | @AllArgsConstructor 11 | public class UserMetric { 12 | 13 | private String name; 14 | private String username; 15 | private String password; 16 | 17 | public void encodePassword(PasswordEncoder passwordEncoder) { 18 | this.password = passwordEncoder.encode(this.password); 19 | } 20 | 21 | public static UserMetric createAdmin() { 22 | return new UserMetric(User.USER_ADMIN_NAME, User.USER_ADMIN_USERNAME, User.USER_ADMIN_PASSWORD); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /example/example-domain/example-domain-user/src/main/java/com/codingapi/example/domain/user/event/UserEvent.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.domain.user.event; 2 | 3 | import com.codingapi.example.domain.user.entity.User; 4 | import com.codingapi.springboot.framework.event.IEvent; 5 | import lombok.Getter; 6 | 7 | public class UserEvent implements IEvent { 8 | 9 | @Getter 10 | private final User user; 11 | 12 | public UserEvent(User user) { 13 | this.user = user; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/example-domain/example-domain-user/src/main/java/com/codingapi/example/domain/user/gateway/PasswordEncoder.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.domain.user.gateway; 2 | 3 | public interface PasswordEncoder { 4 | 5 | String encode(CharSequence rawPassword); 6 | 7 | boolean matches(CharSequence rawPassword, String encodedPassword); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /example/example-domain/example-domain-user/src/main/java/com/codingapi/example/domain/user/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.domain.user.repository; 2 | 3 | 4 | import com.codingapi.example.domain.user.entity.User; 5 | 6 | public interface UserRepository { 7 | 8 | User getUserByUsername(String username); 9 | 10 | User getUserById(long id); 11 | 12 | void save(User user); 13 | 14 | void delete(long id); 15 | } 16 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-flow/src/main/java/com/codingapi/example/infra/flow/entity/BindDataSnapshotEntity.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.flow.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | /** 8 | * 考虑到数据量大的情况下可以根据clazzName分表存储 9 | */ 10 | @Setter 11 | @Getter 12 | @Entity 13 | public class BindDataSnapshotEntity { 14 | /** 15 | * 数据快照id 16 | */ 17 | @Id 18 | @GeneratedValue(strategy = GenerationType.IDENTITY) 19 | private long id; 20 | /** 21 | * 快照信息 22 | */ 23 | @Lob 24 | private String snapshot; 25 | /** 26 | * 创建时间 27 | */ 28 | private long createTime; 29 | 30 | /** 31 | * 数据绑定类名称 32 | */ 33 | private String clazzName; 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-flow/src/main/java/com/codingapi/example/infra/flow/entity/FlowBackupEntity.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.flow.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | @Setter 8 | @Getter 9 | @Entity 10 | public class FlowBackupEntity { 11 | 12 | /** 13 | * 备份id 14 | */ 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.IDENTITY) 17 | private Long id; 18 | 19 | /** 20 | * 流程的字节码 21 | */ 22 | @Lob 23 | private byte[] bytes; 24 | 25 | /** 26 | * 创建时间 27 | */ 28 | private Long createTime; 29 | 30 | /** 31 | * 流程的版本号 32 | * 以流程的修改时间为准 33 | */ 34 | private Long workVersion; 35 | 36 | /** 37 | * 流程的设计id 38 | */ 39 | private Long workId; 40 | } 41 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-flow/src/main/java/com/codingapi/example/infra/flow/entity/FlowProcessEntity.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.flow.entity; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.Id; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | 8 | @Setter 9 | @Getter 10 | @Entity 11 | public class FlowProcessEntity { 12 | 13 | /** 14 | * 流程id 15 | */ 16 | 17 | @Id 18 | private String processId; 19 | 20 | /** 21 | * 流程的字节码 22 | */ 23 | private Long backupId; 24 | 25 | 26 | /** 27 | * 创建时间 28 | */ 29 | private Long createTime; 30 | 31 | /** 32 | * 创建者id 33 | */ 34 | private Long createOperatorId; 35 | 36 | /** 37 | * 是否作废 38 | */ 39 | private Boolean voided; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-flow/src/main/java/com/codingapi/example/infra/flow/entity/FlowWorkEntity.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.flow.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | @Setter 8 | @Getter 9 | @Entity 10 | public class FlowWorkEntity { 11 | 12 | @Id 13 | @GeneratedValue(strategy = GenerationType.IDENTITY) 14 | private Long id; 15 | 16 | @Column(unique = true) 17 | private String code; 18 | 19 | private String title; 20 | 21 | private String description; 22 | 23 | private Long createUser; 24 | 25 | private Long createTime; 26 | 27 | private Long updateTime; 28 | 29 | private Boolean enable; 30 | 31 | /** 32 | * 是否跳过相同审批人,默认为false 33 | */ 34 | private Boolean skipIfSameApprover; 35 | 36 | 37 | private Integer postponedMax; 38 | 39 | @Lob 40 | @Column(name = "m_schema", columnDefinition = "longtext") 41 | private String schema; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-flow/src/main/java/com/codingapi/example/infra/flow/form/LeaveForm.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.flow.form; 2 | 3 | import com.codingapi.example.domain.leave.entity.Leave; 4 | import com.codingapi.springboot.flow.bind.IBindData; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | import lombok.Setter; 9 | 10 | @Setter 11 | @Getter 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | public class LeaveForm implements IBindData { 15 | private long id; 16 | private String desc; 17 | private int days; 18 | private String username; 19 | private long createTime; 20 | 21 | 22 | public Leave toLeave() { 23 | Leave leave = new Leave(); 24 | leave.setId(id); 25 | leave.setUsername(username); 26 | leave.setCreateTime(createTime); 27 | leave.setDays(days); 28 | leave.setDesc(desc); 29 | return leave; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-flow/src/main/java/com/codingapi/example/infra/flow/jpa/BindDataSnapshotEntityRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.flow.jpa; 2 | 3 | import com.codingapi.example.infra.flow.entity.BindDataSnapshotEntity; 4 | import com.codingapi.springboot.fast.jpa.repository.FastRepository; 5 | 6 | public interface BindDataSnapshotEntityRepository extends FastRepository { 7 | 8 | 9 | BindDataSnapshotEntity getBindDataSnapshotEntityById(long id); 10 | 11 | 12 | } 13 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-flow/src/main/java/com/codingapi/example/infra/flow/jpa/FlowBackupEntityRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.flow.jpa; 2 | 3 | import com.codingapi.example.infra.flow.entity.FlowBackupEntity; 4 | import com.codingapi.springboot.fast.jpa.repository.FastRepository; 5 | 6 | public interface FlowBackupEntityRepository extends FastRepository { 7 | 8 | 9 | FlowBackupEntity getFlowBackupEntityById(long id); 10 | 11 | 12 | FlowBackupEntity getFlowBackupEntityByWorkIdAndWorkVersion(long workId,long workVersion); 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-flow/src/main/java/com/codingapi/example/infra/flow/jpa/FlowNodeEntityRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.flow.jpa; 2 | 3 | import com.codingapi.example.infra.flow.entity.FlowNodeEntity; 4 | import com.codingapi.springboot.fast.jpa.repository.FastRepository; 5 | import org.springframework.data.jpa.repository.Modifying; 6 | 7 | import java.util.List; 8 | 9 | public interface FlowNodeEntityRepository extends FastRepository { 10 | 11 | List findFlowNodeEntityByWorkId(long workId); 12 | 13 | @Modifying 14 | void deleteAllByWorkId(long workId); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-flow/src/main/java/com/codingapi/example/infra/flow/jpa/FlowProcessEntityRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.flow.jpa; 2 | 3 | import com.codingapi.example.infra.flow.entity.FlowProcessEntity; 4 | import com.codingapi.springboot.fast.jpa.repository.FastRepository; 5 | 6 | public interface FlowProcessEntityRepository extends FastRepository { 7 | 8 | FlowProcessEntity getFlowProcessEntityByProcessId(String processId); 9 | 10 | void deleteByProcessId(String processId); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-flow/src/main/java/com/codingapi/example/infra/flow/jpa/FlowRelationEntityRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.flow.jpa; 2 | 3 | import com.codingapi.example.infra.flow.entity.FlowRelationEntity; 4 | import com.codingapi.springboot.fast.jpa.repository.FastRepository; 5 | import org.springframework.data.jpa.repository.Modifying; 6 | 7 | import java.util.List; 8 | 9 | public interface FlowRelationEntityRepository extends FastRepository { 10 | 11 | List findFlowRelationEntityByWorkId(long id); 12 | 13 | 14 | @Modifying 15 | void deleteAllByWorkId(long workId); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-flow/src/main/java/com/codingapi/example/infra/flow/jpa/FlowWorkEntityRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.flow.jpa; 2 | 3 | import com.codingapi.example.infra.flow.entity.FlowWorkEntity; 4 | import com.codingapi.springboot.fast.jpa.repository.FastRepository; 5 | 6 | public interface FlowWorkEntityRepository extends FastRepository { 7 | 8 | 9 | FlowWorkEntity getFlowWorkEntityById(long id); 10 | 11 | FlowWorkEntity getFlowWorkEntityByCode(String code); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-flow/src/main/java/com/codingapi/example/infra/flow/user/FlowUser.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.flow.user; 2 | 3 | import com.codingapi.example.domain.user.entity.User; 4 | import com.codingapi.springboot.flow.user.IFlowOperator; 5 | 6 | public class FlowUser implements IFlowOperator { 7 | 8 | private final User user; 9 | 10 | public FlowUser(User user) { 11 | this.user = user; 12 | } 13 | 14 | @Override 15 | public long getUserId() { 16 | return user.getId(); 17 | } 18 | 19 | @Override 20 | public String getName() { 21 | return user.getName(); 22 | } 23 | 24 | @Override 25 | public boolean isFlowManager() { 26 | return user.isFlowManager(); 27 | } 28 | 29 | @Override 30 | public IFlowOperator entrustOperator() { 31 | if(user.getEntrustOperator()!=null) { 32 | return new FlowUser(user.getEntrustOperator()); 33 | }else { 34 | return null; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-jpa/src/main/java/com/codingapi/example/infra/db/entity/LeaveEntity.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.db.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | @Setter 8 | @Getter 9 | @Entity 10 | public class LeaveEntity { 11 | 12 | @Id 13 | @GeneratedValue(strategy = GenerationType.IDENTITY) 14 | private long id; 15 | 16 | @Column(name = "m_desc") 17 | private String desc; 18 | private int days; 19 | private String username; 20 | private long createTime; 21 | } 22 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-jpa/src/main/java/com/codingapi/example/infra/db/entity/TestEntity.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.db.entity; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.GenerationType; 6 | import jakarta.persistence.Id; 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Setter 12 | @Getter 13 | @Entity 14 | @NoArgsConstructor 15 | public class TestEntity { 16 | 17 | @Id 18 | @GeneratedValue(strategy = GenerationType.IDENTITY) 19 | private long id; 20 | 21 | private String name; 22 | 23 | public TestEntity(String name) { 24 | this.name = name; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-jpa/src/main/java/com/codingapi/example/infra/db/entity/UserEntity.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.db.entity; 2 | 3 | import com.codingapi.example.domain.user.entity.UserMetric; 4 | import jakarta.persistence.*; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | 8 | @Setter 9 | @Getter 10 | @Entity 11 | public class UserEntity { 12 | 13 | @Id 14 | @GeneratedValue(strategy = GenerationType.IDENTITY) 15 | private long id; 16 | 17 | private String name; 18 | 19 | @Column(unique = true) 20 | private String username; 21 | 22 | private String password; 23 | 24 | private boolean isFlowManager; 25 | 26 | private long entrustOperatorId; 27 | 28 | private String entrustOperatorName; 29 | 30 | private long createTime; 31 | 32 | public UserMetric getUserMetric() { 33 | return new UserMetric(name,username,password); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-jpa/src/main/java/com/codingapi/example/infra/db/jpa/LeaveEntityRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.db.jpa; 2 | 3 | import com.codingapi.example.infra.db.entity.LeaveEntity; 4 | import com.codingapi.springboot.fast.jpa.repository.FastRepository; 5 | 6 | public interface LeaveEntityRepository extends FastRepository { 7 | 8 | 9 | LeaveEntity getLeaveEntityById(long id); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-jpa/src/main/java/com/codingapi/example/infra/db/jpa/TestEntityRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.db.jpa; 2 | 3 | import com.codingapi.example.infra.db.entity.TestEntity; 4 | import com.codingapi.springboot.fast.jpa.repository.FastRepository; 5 | 6 | public interface TestEntityRepository extends FastRepository { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-jpa/src/main/java/com/codingapi/example/infra/db/jpa/UserEntityRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.db.jpa; 2 | 3 | import com.codingapi.example.infra.db.entity.UserEntity; 4 | import com.codingapi.springboot.fast.jpa.repository.FastRepository; 5 | 6 | import java.util.List; 7 | 8 | public interface UserEntityRepository extends FastRepository { 9 | 10 | UserEntity getUserEntityByUsername(String username); 11 | 12 | UserEntity getUserEntityById(long id); 13 | 14 | 15 | List findUserEntityByIdIn(List ids); 16 | } 17 | -------------------------------------------------------------------------------- /example/example-infra/example-infra-security/src/main/java/com/codingapi/example/infra/security/gateway/PasswordEncoderImpl.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.infra.security.gateway; 2 | 3 | import com.codingapi.example.domain.user.gateway.PasswordEncoder; 4 | import org.springframework.stereotype.Repository; 5 | 6 | @Repository 7 | public class PasswordEncoderImpl implements PasswordEncoder, org.springframework.security.crypto.password.PasswordEncoder { 8 | 9 | private final org.springframework.security.crypto.password.PasswordEncoder passwordEncoder = new org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder(); 10 | 11 | @Override 12 | public String encode(CharSequence rawPassword) { 13 | return passwordEncoder.encode(rawPassword); 14 | } 15 | 16 | @Override 17 | public boolean matches(CharSequence rawPassword, String encodedPassword) { 18 | return passwordEncoder.matches(rawPassword, encodedPassword); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /example/example-interface/src/main/java/com/codingapi/example/api/query/LeaveQueryController.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.api.query; 2 | 3 | import com.codingapi.example.app.query.service.LeaveQueryService; 4 | import com.codingapi.example.infra.db.entity.LeaveEntity; 5 | import com.codingapi.springboot.framework.dto.request.SearchRequest; 6 | import com.codingapi.springboot.framework.dto.response.MultiResponse; 7 | import lombok.AllArgsConstructor; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | @RestController 13 | @RequestMapping("/api/query/leave") 14 | @AllArgsConstructor 15 | public class LeaveQueryController { 16 | 17 | private final LeaveQueryService leaveQueryService; 18 | 19 | @GetMapping("/list") 20 | public MultiResponse list(SearchRequest searchRequest){ 21 | return MultiResponse.of(leaveQueryService.list(searchRequest)); 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /example/example-interface/src/main/java/com/codingapi/example/api/query/UserQueryController.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.api.query; 2 | 3 | import com.codingapi.example.app.query.service.UserQueryService; 4 | import com.codingapi.example.infra.db.entity.UserEntity; 5 | import com.codingapi.springboot.framework.dto.request.SearchRequest; 6 | import com.codingapi.springboot.framework.dto.response.MultiResponse; 7 | import lombok.AllArgsConstructor; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | @RestController 13 | @RequestMapping("/api/query/user") 14 | @AllArgsConstructor 15 | public class UserQueryController { 16 | 17 | private final UserQueryService userQueryService; 18 | 19 | @GetMapping("/list") 20 | public MultiResponse list(SearchRequest searchRequest) { 21 | return MultiResponse.of(userQueryService.list(searchRequest)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/example-interface/src/main/java/com/codingapi/example/handler/LeaveHandler.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.handler; 2 | 3 | import com.codingapi.example.domain.leave.service.LeaveService; 4 | import com.codingapi.example.infra.flow.form.LeaveForm; 5 | import com.codingapi.springboot.flow.event.FlowApprovalEvent; 6 | import com.codingapi.springboot.framework.event.IHandler; 7 | import lombok.AllArgsConstructor; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.stereotype.Service; 10 | 11 | @Slf4j 12 | @Service 13 | @AllArgsConstructor 14 | public class LeaveHandler implements IHandler { 15 | 16 | private final LeaveService leaveService; 17 | 18 | @Override 19 | public void handler(FlowApprovalEvent event) { 20 | log.info("LeaveHandler: {}", event); 21 | if (event.isFinish() && event.match(LeaveForm.class)) { 22 | LeaveForm form = (LeaveForm) event.getBindData(); 23 | leaveService.create(form.toLeave()); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /example/example-interface/src/main/java/com/codingapi/example/runner/UserRunner.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example.runner; 2 | 3 | import com.codingapi.example.domain.user.service.UserService; 4 | import lombok.AllArgsConstructor; 5 | import org.springframework.boot.ApplicationArguments; 6 | import org.springframework.boot.ApplicationRunner; 7 | import org.springframework.stereotype.Service; 8 | 9 | @Service 10 | @AllArgsConstructor 11 | public class UserRunner implements ApplicationRunner { 12 | 13 | private final UserService userService; 14 | 15 | @Override 16 | public void run(ApplicationArguments args) throws Exception { 17 | userService.initAdmin(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /example/example-server/src/main/java/com/codingapi/example/ServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.example; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ServerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ServerApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /mobile-ui/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | /.idea 4 | 5 | # dependencies 6 | /node_modules 7 | /.pnp 8 | .pnp.js 9 | 10 | # testing 11 | /coverage 12 | 13 | # production 14 | /build 15 | /dist 16 | 17 | # misc 18 | .DS_Store 19 | .env.local 20 | .env.development.local 21 | .env.test.local 22 | .env.production.local 23 | 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | yarn.lock 28 | package-lock.json 29 | 30 | -------------------------------------------------------------------------------- /mobile-ui/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'jsdom', 4 | moduleNameMapper: { 5 | '\\.(css|less|scss|sass)$': 'identity-obj-proxy', 6 | }, 7 | setupFilesAfterEnv: ['/jest.setup.ts'], 8 | }; -------------------------------------------------------------------------------- /mobile-ui/jest.setup.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | 3 | Object.defineProperty(window, 'matchMedia', { 4 | writable: true, 5 | value: jest.fn().mockImplementation(query => ({ 6 | matches: false, 7 | media: query, 8 | onchange: null, 9 | addListener: jest.fn(), // 旧版 API 10 | removeListener: jest.fn(), // 旧版 API 11 | addEventListener: jest.fn(), // 新版 API 12 | removeEventListener: jest.fn(), // 新版 API 13 | dispatchEvent: jest.fn(), 14 | })), 15 | }); -------------------------------------------------------------------------------- /mobile-ui/jest/map.test.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | 3 | 4 | test("map", () => { 5 | const map = new Map(); 6 | map.set('key', 'value'); 7 | expect(map.get('key')).toBe('value'); 8 | expect(map.has('key')).toBe(true); 9 | expect(map.size).toBe(1); 10 | map.delete('key'); 11 | expect(map.has('key')).toBe(false); 12 | expect(map.size).toBe(0); 13 | }) -------------------------------------------------------------------------------- /mobile-ui/mocks/product.ts: -------------------------------------------------------------------------------- 1 | import Mock from "mockjs"; 2 | import webpackMockServer from "webpack-mock-server"; 3 | 4 | export default webpackMockServer.add((app, helper) => { 5 | app.get('/api/products', (req, res) => { 6 | const products = Mock.mock({ 7 | 'list|100': [{ 8 | 'id|+1': 1, 9 | 'name': '@name', 10 | 'price|100-1000': 1, 11 | }] 12 | }).list; 13 | 14 | res.json(products); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /mobile-ui/mocks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": [ 4 | "../mocks/*", 5 | "*.mock.ts", 6 | "**/global.d.ts" 7 | ], 8 | "files": [], 9 | "exclude": [ 10 | "*test.mock.ts" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /mobile-ui/mocks/user.ts: -------------------------------------------------------------------------------- 1 | import webpackMockServer from "webpack-mock-server"; 2 | 3 | export default webpackMockServer.add((app, helper) => { 4 | app.post('/user/login', (req, res) => { 5 | const username = req.body.username; 6 | if(username==='admin'){ 7 | res.json({ 8 | success:true, 9 | data:{ 10 | 'username': username, 11 | 'token':'test token', 12 | 'avatar':'/logo.png', 13 | 'authorities': ['ROLE_ADMIN','ROLE_DEVELOPER'], 14 | } 15 | }); 16 | return; 17 | } 18 | 19 | res.json({ 20 | success:true, 21 | data:{ 22 | 'username': username, 23 | 'token':'test token', 24 | 'avatar':'/logo.png', 25 | 'authorities': ['ROLE_USER'], 26 | } 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /mobile-ui/public/captcha.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingapi/springboot-framework/79e75cf02383c413eec0ae8c798f7302e0de543e/mobile-ui/public/captcha.jpeg -------------------------------------------------------------------------------- /mobile-ui/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingapi/springboot-framework/79e75cf02383c413eec0ae8c798f7302e0de543e/mobile-ui/public/favicon.ico -------------------------------------------------------------------------------- /mobile-ui/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingapi/springboot-framework/79e75cf02383c413eec0ae8c798f7302e0de543e/mobile-ui/public/logo.png -------------------------------------------------------------------------------- /mobile-ui/readme.md: -------------------------------------------------------------------------------- 1 | # Mobile-ui with Antd For Micro Frontends 2 | 3 | This is a Simple React App with Webpack5 & Typescript. 4 | 5 | ## Features 6 | 1. Support Webpack 5 ModuleFederationPlugin for Micro Frontends 7 | 2. Support Dynamic zip component loading 8 | 3. Support Dynamic Routing & Dynamic Menu 9 | 4. Support Axios for API calls 10 | 5. Support Antd-Mobile UI Library 11 | 6. Support Redux for State Management 12 | 7. Support Mock Server for API Mocking 13 | 8. Support Access Components 14 | 9. Support Jest for Unit Testing 15 | 10. Support DockerCompose for Deployment 16 | 17 | ## Running 18 | ```shell 19 | yarn 20 | 21 | yarn start 22 | ``` 23 | ## Build 24 | ```shell 25 | yarn build 26 | ``` 27 | 28 | ## Deploy 29 | ```shell 30 | cd scripts 31 | sh package.sh 32 | sh deploy.sh 33 | ``` 34 | 35 | -------------------------------------------------------------------------------- /mobile-ui/scripts/.gitignore: -------------------------------------------------------------------------------- 1 | /mobile 2 | -------------------------------------------------------------------------------- /mobile-ui/scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | serverHost=server 2 | serverAccount=root 3 | serverPort=22 4 | serverPath=/opt/test/ 5 | 6 | 7 | scp -o ConnectTimeout=30 -P $serverPort -r * $serverAccount@$serverHost:$serverPath 8 | ssh -p $serverPort $serverAccount@$serverHost "cd $serverPath && sed -i 's/\r//g' *.sh && sh install.sh" 9 | -------------------------------------------------------------------------------- /mobile-ui/scripts/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | admin-nginx: 5 | image: nginx:latest 6 | volumes: 7 | - "./admin:/usr/share/nginx/html" 8 | environment: 9 | TZ: "Asia/Shanghai" 10 | restart: always 11 | ports: 12 | - "13000:80" -------------------------------------------------------------------------------- /mobile-ui/scripts/install.sh: -------------------------------------------------------------------------------- 1 | docker-compose build --no-cache 2 | docker-compose up -d 3 | docker ps -a -------------------------------------------------------------------------------- /mobile-ui/scripts/package.sh: -------------------------------------------------------------------------------- 1 | rm -rf mobile 2 | 3 | cd .. 4 | yarn 5 | yarn run build 6 | 7 | 8 | cp -r ./dist/ ./scripts/mobile/ -------------------------------------------------------------------------------- /mobile-ui/src/api/account.ts: -------------------------------------------------------------------------------- 1 | import {httpClient} from "@/api"; 2 | 3 | export async function captcha() { 4 | return httpClient.get('/open/captcha'); 5 | } 6 | 7 | export async function login(body: any) { 8 | return httpClient.post('/user/login', body); 9 | } 10 | 11 | export function initUser(user: { 12 | username: string; 13 | token: string; 14 | authorities: string[]; 15 | avatar: string; 16 | data: any; 17 | }) { 18 | const { username, token, authorities, avatar, data } = user; 19 | localStorage.setItem('username', username); 20 | localStorage.setItem('token', token); 21 | } 22 | 23 | 24 | export function clearUser() { 25 | localStorage.removeItem('username'); 26 | localStorage.removeItem('token'); 27 | } 28 | -------------------------------------------------------------------------------- /mobile-ui/src/api/index.ts: -------------------------------------------------------------------------------- 1 | import {Toast} from "antd-mobile"; 2 | import {HttpClient} from "@codingapi/ui-framework"; 3 | 4 | export const httpClient = new HttpClient(10000,{ 5 | success: (msg: string) => { 6 | Toast.show({ 7 | content: msg, 8 | }) 9 | }, 10 | error: (msg: string) => { 11 | Toast.show({ 12 | icon: 'fail', 13 | content: msg, 14 | }) 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /mobile-ui/src/api/leave.ts: -------------------------------------------------------------------------------- 1 | import {httpClient} from "@/api/index"; 2 | 3 | export async function list( 4 | lastId?: string, 5 | pageSize=10, 6 | ) { 7 | return httpClient.get('/api/app/query/leave/list', {lastId,pageSize}); 8 | } 9 | 10 | 11 | export async function startLeave(body: any) { 12 | return httpClient.post('/api/cmd/leave/startLeave', body); 13 | } 14 | 15 | -------------------------------------------------------------------------------- /mobile-ui/src/api/oss.ts: -------------------------------------------------------------------------------- 1 | import {httpClient} from "@/api/index"; 2 | 3 | 4 | export async function loadFiles(ids: string) { 5 | return httpClient.get('/api/oss/load', {ids: ids}); 6 | } 7 | 8 | 9 | export async function upload(body: any) { 10 | return httpClient.post('/api/oss/upload', body); 11 | } 12 | -------------------------------------------------------------------------------- /mobile-ui/src/assets/flow/done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingapi/springboot-framework/79e75cf02383c413eec0ae8c798f7302e0de543e/mobile-ui/src/assets/flow/done.png -------------------------------------------------------------------------------- /mobile-ui/src/assets/flow/todo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingapi/springboot-framework/79e75cf02383c413eec0ae8c798f7302e0de543e/mobile-ui/src/assets/flow/todo.png -------------------------------------------------------------------------------- /mobile-ui/src/assets/flow/un_submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codingapi/springboot-framework/79e75cf02383c413eec0ae8c798f7302e0de543e/mobile-ui/src/assets/flow/un_submit.png -------------------------------------------------------------------------------- /mobile-ui/src/components/info/FormInfo/index.scss: -------------------------------------------------------------------------------- 1 | @use "@/config/variables" as *; 2 | 3 | .form-info { 4 | background-color: white; 5 | margin-top: 5px; 6 | margin-bottom: 5px; 7 | padding: 5px; 8 | width: 100%; 9 | } 10 | 11 | .form-header-title { 12 | width: 100%; 13 | height: 20px; 14 | border-left: 4px solid $theme-primary-color; 15 | padding-left: 4px; 16 | font-size: $content-font-size; 17 | margin-bottom: 10px; 18 | } 19 | 20 | .form-content { 21 | width: 100%; 22 | border-bottom: 2px solid $body-background-color; 23 | 24 | .label { 25 | font-size: $content-font-size; 26 | display: flex; 27 | align-items: center; 28 | } 29 | 30 | .value { 31 | font-size: $content-font-size; 32 | display: flex; 33 | align-items: center; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /mobile-ui/src/components/info/FormInfo/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import {Form} from "@codingapi/form-mobile"; 3 | import "./index.scss"; 4 | import {FormProps} from "@codingapi/ui-framework"; 5 | 6 | interface FormInfoProps extends FormProps { 7 | title: string; 8 | } 9 | 10 | const FormInfo: React.FC = (props) => { 11 | return ( 12 |
13 |
{props.title}
14 |
15 |
16 |
17 |
18 | ) 19 | } 20 | 21 | export default FormInfo; 22 | -------------------------------------------------------------------------------- /mobile-ui/src/config/flows.tsx: -------------------------------------------------------------------------------- 1 | import LeaveForm from "@/pages/leave/form"; 2 | 3 | export const flowViews = { 4 | "default":LeaveForm 5 | } 6 | -------------------------------------------------------------------------------- /mobile-ui/src/config/register.component.tsx: -------------------------------------------------------------------------------- 1 | import "@/components/flow/register"; 2 | -------------------------------------------------------------------------------- /mobile-ui/src/config/theme.tsx: -------------------------------------------------------------------------------- 1 | 2 | export const theme = { 3 | token: { 4 | colorPrimary: '#4a79d8', 5 | } 6 | }; 7 | 8 | 9 | export const config = { 10 | // 主题配置 11 | theme: theme, 12 | // 后台名称 13 | title: 'Admin-UI', 14 | // 后台logo 15 | logo: 'static://assets/logo.png', 16 | // 欢迎页路径 17 | welcomePath: '/', 18 | // 登录页路径 19 | loginPath: '/login', 20 | // 侧边栏宽度 21 | siderWidth: 210, 22 | // 侧边栏布局 23 | layout: 'top' as 'side' | 'top' | 'mix', 24 | // 水印 25 | waterMark: 'default waterMark', 26 | } 27 | 28 | -------------------------------------------------------------------------------- /mobile-ui/src/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' { 2 | const content: any; 3 | export default content; 4 | } 5 | 6 | declare module '*.png' { 7 | const content: any; 8 | export default content; 9 | } 10 | 11 | declare module '*.jpg' { 12 | const content: any; 13 | export default content; 14 | } 15 | 16 | declare module '*.gif' { 17 | const content: any; 18 | export default content; 19 | } 20 | 21 | 22 | -------------------------------------------------------------------------------- /mobile-ui/src/gateway/default/Header.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import {HeaderProps} from "@/gateway"; 3 | 4 | 5 | const HeaderDefault: React.FC = (props) => { 6 | return ( 7 |
8 |

{props.title}

9 | 10 |
11 | PS:local default component 12 |
13 |
14 | ) 15 | } 16 | 17 | export default HeaderDefault; 18 | -------------------------------------------------------------------------------- /mobile-ui/src/gateway/index.tsx: -------------------------------------------------------------------------------- 1 | 2 | export interface HeaderProps{ 3 | title: string; 4 | onClick: () => void; 5 | } 6 | 7 | -------------------------------------------------------------------------------- /mobile-ui/src/layout/Footer/index.scss: -------------------------------------------------------------------------------- 1 | @use "@/styles/variable" as *; 2 | 3 | .page-footer { 4 | width: 100%; 5 | height: $page-footer-height; 6 | background-color: white; 7 | display: flex; 8 | justify-content: center; 9 | align-items: center; 10 | box-shadow: inset 0 1px 0 $body-background-color; 11 | } 12 | -------------------------------------------------------------------------------- /mobile-ui/src/layout/Footer/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./index.scss"; 3 | 4 | interface FooterLayoutProps { 5 | children?: React.ReactNode; 6 | } 7 | 8 | const FooterLayout: React.FC = (props) => { 9 | 10 | return ( 11 |
14 | {props.children} 15 |
16 | ) 17 | } 18 | 19 | export default FooterLayout; 20 | -------------------------------------------------------------------------------- /mobile-ui/src/layout/Header/index.scss: -------------------------------------------------------------------------------- 1 | @use "@/styles/variable" as *; 2 | 3 | .page-header { 4 | background-color: white; 5 | height: $page-header-height !important; 6 | width: 100%; 7 | margin: 0 !important; 8 | padding: 0 !important; 9 | box-shadow: inset 0 0 0 1px $body-background-color; 10 | } 11 | -------------------------------------------------------------------------------- /mobile-ui/src/layout/Header/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import {NavBar} from "antd-mobile"; 3 | import {useNavigate} from "react-router"; 4 | import "./index.scss"; 5 | 6 | interface HeaderLayoutProps{ 7 | children: React.ReactNode; 8 | isHome?:boolean; 9 | left?:React.ReactNode; 10 | right?:React.ReactNode; 11 | } 12 | 13 | const HeaderLayout:React.FC = (props)=>{ 14 | const navigate = useNavigate(); 15 | 16 | const back = ()=>{ 17 | navigate(-1); 18 | } 19 | 20 | return ( 21 | 28 | {props.children} 29 | 30 | ) 31 | } 32 | 33 | export default HeaderLayout; 34 | -------------------------------------------------------------------------------- /mobile-ui/src/layout/NotFound/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import {Button, Result} from "antd-mobile"; 3 | import {useNavigate} from "react-router"; 4 | import {config} from "@/config/theme"; 5 | 6 | const Index = () => { 7 | const navigate = useNavigate(); 8 | 9 | const goHome = () => { 10 | navigate(config.welcomePath, {replace: true}); 11 | } 12 | 13 | return ( 14 | 19 |
请检查您的地址是否正确
20 | 23 |
24 | )} 25 | /> 26 | ) 27 | } 28 | 29 | export default Index; 30 | -------------------------------------------------------------------------------- /mobile-ui/src/layout/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import {Routes} from "react-router"; 3 | import {loadLayoutRoutes} from "@/config/route"; 4 | import {Provider} from "react-redux"; 5 | import {layoutStore} from "@/sotre/LayoutSlice"; 6 | 7 | 8 | const $Layout = () => { 9 | return ( 10 | <> 11 |
12 | 13 | {loadLayoutRoutes()} 14 | 15 |
16 | 17 | ) 18 | } 19 | 20 | 21 | const Layout = () => { 22 | return ( 23 | 24 | <$Layout/> 25 | 26 | ) 27 | } 28 | 29 | export default Layout; 30 | -------------------------------------------------------------------------------- /mobile-ui/src/pages/home/index.scss: -------------------------------------------------------------------------------- 1 | .content { 2 | height: 120px; 3 | color: #ffffff; 4 | display: flex; 5 | justify-content: center; 6 | align-items: center; 7 | font-size: 48px; 8 | user-select: none; 9 | } 10 | -------------------------------------------------------------------------------- /mobile-ui/src/pages/leave/create.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Header from "@/layout/Header"; 3 | import {FlowView} from "@codingapi/flow-mobile"; 4 | import LeaveForm from "@/pages/leave/form"; 5 | import {useNavigate} from "react-router"; 6 | 7 | const LeaveCreatePage = () => { 8 | 9 | const username = localStorage.getItem('username'); 10 | const navigate = useNavigate(); 11 | 12 | return ( 13 |
14 |
发起请假
15 | { 19 | navigate(-1); 20 | }} 21 | visible={true} 22 | formParams={{ 23 | days:1, 24 | clazzName: 'com.codingapi.example.infra.flow.form.LeaveForm', 25 | username: username 26 | }} 27 | /> 28 |
29 | ) 30 | } 31 | 32 | export default LeaveCreatePage; 33 | -------------------------------------------------------------------------------- /mobile-ui/src/pages/leave/detail.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Header from "@/layout/Header"; 3 | import {useLocation} from "react-router"; 4 | import {Descriptions} from "@codingapi/form-mobile"; 5 | import {fields} from "@/pages/leave/fields"; 6 | 7 | const LeaveDetailPage = () => { 8 | 9 | const location = useLocation(); 10 | const state = location.state; 11 | 12 | return ( 13 | <> 14 |
流程详情
15 | { 18 | return state; 19 | }} 20 | /> 21 | 22 | ) 23 | } 24 | 25 | export default LeaveDetailPage; 26 | -------------------------------------------------------------------------------- /mobile-ui/src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /mobile-ui/src/sotre/LayoutSlice.ts: -------------------------------------------------------------------------------- 1 | import {configureStore, createSlice, PayloadAction} from '@reduxjs/toolkit'; 2 | 3 | export interface LayoutStore { 4 | title: string; 5 | backHome:boolean; 6 | } 7 | 8 | export type MenuStoreAction = { 9 | changeTitle: (state: LayoutStore, action: PayloadAction) => void; 10 | } 11 | 12 | export const layoutSlice = createSlice({ 13 | name: 'layout', 14 | initialState: { 15 | title: '首页', 16 | backHome:true 17 | }, 18 | reducers: { 19 | changeTitle: (state,action) => { 20 | const title = action.payload; 21 | state.title = title; 22 | state.backHome = '首页' === title; 23 | } 24 | }, 25 | }); 26 | 27 | export const {changeTitle} = layoutSlice.actions; 28 | 29 | export const layoutStore = configureStore({ 30 | reducer: { 31 | layout: layoutSlice.reducer 32 | }, 33 | }); 34 | 35 | export type LayoutState = ReturnType; 36 | 37 | 38 | -------------------------------------------------------------------------------- /mobile-ui/src/styles/index.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --primary-color: #0f58ea; 3 | --body-background-color: #e6e7ea; 4 | 5 | --content-font-size-large: 24px; 6 | --content-font-size-middle: 16px; 7 | --content-font-size-small: 12px; 8 | 9 | --content-font-size: var(--content-font-size-middle); 10 | } 11 | 12 | 13 | :root:root{ 14 | --adm-color-primary: var(--primary-color); 15 | } 16 | 17 | 18 | body { 19 | margin: 0; 20 | padding: 0; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | background-color: var(--body-background-color); 24 | font-size: var(--content-font-size); 25 | } 26 | 27 | code { 28 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 29 | monospace; 30 | } 31 | -------------------------------------------------------------------------------- /mobile-ui/src/styles/mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin flex-center { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | width: 100%; 6 | } 7 | 8 | @mixin flex-right { 9 | display: flex; 10 | justify-content: right; 11 | align-items: center; 12 | width: 100%; 13 | } -------------------------------------------------------------------------------- /mobile-ui/src/styles/variable.scss: -------------------------------------------------------------------------------- 1 | // 主题颜色 2 | $theme-primary-color: var(--primary-color,#4a79d8); 3 | // 背景颜色 4 | $body-background-color: var(--body-background-color,#e6e7ea); 5 | // header颜色 6 | $header-background-color: white; 7 | // FormPlaceholder颜色 8 | $from-placeholder-color: #c4c4c4; 9 | // 导航栏的高度 10 | $page-header-height: 50px; 11 | // Footer栏的高度 12 | $page-footer-height: 50px; 13 | // 页面内容区域的高度 14 | $page-content-height: calc(100vh - #{$page-header-height} - #{$page-footer-height}); 15 | // 标题字体大小 16 | $title-font-size: var(--content-font-size-middle,16px); 17 | // 内容字体大小 18 | $content-font-size:var(--content-font-size,12px); -------------------------------------------------------------------------------- /mobile-ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": false, 21 | "jsx": "react-jsx", 22 | "baseUrl": ".", 23 | "paths": { 24 | "@/*": ["src/*"] 25 | } 26 | }, 27 | "include": [ 28 | "src" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /mobile-ui/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | const { merge } = require('webpack-merge'); 2 | const common = require('./webpack.common.js'); 3 | 4 | module.exports = merge(common, { 5 | mode: 'development', 6 | devServer: { 7 | port: 10000, 8 | proxy: [ 9 | { 10 | context: ['/api', '/open', '/user'], 11 | target: 'http://localhost:8090', 12 | changeOrigin: true, 13 | logLevel: 'debug', 14 | onProxyReq: (proxyReq, req, res) => { 15 | console.log('Proxying request:', req.url); 16 | }, 17 | } 18 | ] 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /mobile-ui/webpack.config.mock.js: -------------------------------------------------------------------------------- 1 | const {merge} = require('webpack-merge'); 2 | const common = require('./webpack.common.js'); 3 | const webpackMockServer = require('webpack-mock-server'); 4 | 5 | module.exports = merge(common, { 6 | mode: 'development', 7 | devServer: { 8 | port: 10000, 9 | 10 | setupMiddlewares: (middlewares, devServer) => { 11 | if (!devServer) { 12 | throw new Error('webpack-dev-server is not defined'); 13 | } 14 | // 使用 webpackMockServer 来添加 mock 功能 15 | webpackMockServer.use(devServer.app,{ 16 | port: 8090, 17 | entry:[ 18 | './mocks/user.ts', 19 | './mocks/product.ts', 20 | ], 21 | tsConfigFileName: "mocks/tsconfig.json" 22 | }); 23 | 24 | console.log('mock server is running'); 25 | return middlewares; // 返回 middlewares 26 | } 27 | }, 28 | }); 29 | -------------------------------------------------------------------------------- /mobile-ui/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | const {merge} = require('webpack-merge'); 2 | const common = require('./webpack.common.js'); 3 | 4 | module.exports = merge(common,{ 5 | mode: 'production', 6 | devServer: { 7 | port: 10000, 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/exception/NotAuthorizationException.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.exception; 2 | 3 | import java.sql.SQLException; 4 | 5 | public class NotAuthorizationException extends SQLException { 6 | 7 | public NotAuthorizationException() { 8 | } 9 | 10 | public NotAuthorizationException(String reason) { 11 | super(reason); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/filter/DefaultDataAuthorizationFilter.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.filter; 2 | 3 | import com.codingapi.springboot.authorization.handler.Condition; 4 | 5 | public class DefaultDataAuthorizationFilter implements DataAuthorizationFilter{ 6 | 7 | @Override 8 | public T columnAuthorization(String tableName, String columnName, T value) { 9 | return value; 10 | } 11 | 12 | @Override 13 | public Condition rowAuthorization(String tableName, String tableAlias) { 14 | return null; 15 | } 16 | 17 | @Override 18 | public boolean supportColumnAuthorization(String tableName, String columnName, Object value) { 19 | return false; 20 | } 21 | 22 | @Override 23 | public boolean supportRowAuthorization(String tableName, String tableAlias) { 24 | return false; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/handler/Condition.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.handler; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * 查询条件 7 | */ 8 | @Getter 9 | public class Condition { 10 | 11 | private final String condition; 12 | 13 | private Condition(String condition) { 14 | this.condition = condition; 15 | } 16 | 17 | public static Condition customCondition(String condition) { 18 | return new Condition(condition); 19 | } 20 | 21 | public static Condition formatCondition(String condition, Object... args) { 22 | return new Condition(String.format(condition, args)); 23 | } 24 | 25 | public static Condition emptyCondition() { 26 | return null; 27 | } 28 | 29 | public static Condition defaultCondition() { 30 | return new Condition("1=1"); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/handler/DefaultRowHandler.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.handler; 2 | 3 | import com.codingapi.springboot.authorization.DataAuthorizationContext; 4 | 5 | public class DefaultRowHandler implements RowHandler { 6 | 7 | @Override 8 | public Condition handler(String subSql, String tableName, String tableAlias) { 9 | return DataAuthorizationContext.getInstance().rowAuthorization(tableName, tableAlias); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/handler/RowHandler.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.handler; 2 | 3 | /** 4 | * 行数据权限处理器 5 | */ 6 | public interface RowHandler { 7 | 8 | /** 9 | * 查询条件拦截 10 | * 11 | * @param subSql 查询子SQL语句 12 | * @param tableName 表名 13 | * @param tableAlias 表别名 14 | * @return 条件语句 15 | */ 16 | Condition handler(String subSql, String tableName, String tableAlias); 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/handler/RowHandlerContext.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.handler; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Setter 7 | public class RowHandlerContext { 8 | 9 | @Getter 10 | private final static RowHandlerContext instance = new RowHandlerContext(); 11 | 12 | @Getter 13 | private RowHandler rowHandler; 14 | 15 | private RowHandlerContext() { 16 | this.rowHandler = new DefaultRowHandler(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/interceptor/DataPermissionSQL.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.interceptor; 2 | 3 | import com.codingapi.springboot.authorization.enhancer.TableColumnAliasContext; 4 | import lombok.Getter; 5 | 6 | @Getter 7 | public class DataPermissionSQL { 8 | 9 | private final String sql; 10 | private final String newSql; 11 | private final TableColumnAliasContext aliasContext; 12 | 13 | public DataPermissionSQL(String sql, String newSql, TableColumnAliasContext aliasContext) { 14 | this.sql = sql; 15 | this.newSql = newSql; 16 | this.aliasContext = aliasContext; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/interceptor/SQLInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.interceptor; 2 | 3 | import java.sql.SQLException; 4 | 5 | /** 6 | * SQL查询条件处理器 7 | */ 8 | public interface SQLInterceptor { 9 | 10 | 11 | /** 12 | * 前置处理 13 | * 14 | * @param sql sql 15 | * @return 是否处理 16 | */ 17 | boolean beforeHandler(String sql); 18 | 19 | 20 | /** 21 | * 处理sql 22 | * 23 | * @param sql sql 24 | * @return 处理后的sql newSql 25 | * @throws SQLException 26 | */ 27 | DataPermissionSQL postHandler(String sql) throws SQLException; 28 | 29 | 30 | /** 31 | * 后置处理 32 | * @param sql sql 33 | * @param newSql newSql 34 | * @param exception exception 35 | */ 36 | void afterHandler(String sql, String newSql, SQLException exception); 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/interceptor/SQLInterceptorContext.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.interceptor; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Setter 7 | public class SQLInterceptorContext { 8 | 9 | @Getter 10 | private final static SQLInterceptorContext instance = new SQLInterceptorContext(); 11 | 12 | @Getter 13 | private SQLInterceptor sqlInterceptor; 14 | 15 | private SQLInterceptorContext() { 16 | this.sqlInterceptor = new DefaultSQLInterceptor(); 17 | } 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/mask/ColumnMask.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.mask; 2 | 3 | /** 4 | * 列数据脱敏 5 | */ 6 | public interface ColumnMask { 7 | 8 | boolean support(Object value); 9 | 10 | Object mask(Object value); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/mask/ColumnMaskContext.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.mask; 2 | 3 | import lombok.Getter; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class ColumnMaskContext { 9 | 10 | private final List columnMasks; 11 | 12 | private ColumnMaskContext() { 13 | this.columnMasks = new ArrayList<>(); 14 | } 15 | 16 | public void addColumnMask(ColumnMask columnMask) { 17 | this.columnMasks.add(columnMask); 18 | } 19 | 20 | @Getter 21 | private final static ColumnMaskContext instance = new ColumnMaskContext(); 22 | 23 | 24 | public T mask(T value) { 25 | for (ColumnMask columnMask : columnMasks) { 26 | if (columnMask.support(value)) { 27 | return (T)columnMask.mask(value); 28 | } 29 | } 30 | return value; 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/properties/DataAuthorizationProperties.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.properties; 2 | 3 | 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | @Setter 8 | @Getter 9 | public class DataAuthorizationProperties { 10 | 11 | private boolean showSql = false; 12 | 13 | public DataAuthorizationProperties() { 14 | DataAuthorizationPropertyContext.getInstance().setDataAuthorizationProperties(this); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/properties/DataAuthorizationPropertyContext.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.properties; 2 | 3 | import lombok.Getter; 4 | 5 | public class DataAuthorizationPropertyContext { 6 | 7 | @Getter 8 | private final static DataAuthorizationPropertyContext instance = new DataAuthorizationPropertyContext(); 9 | 10 | private DataAuthorizationPropertyContext(){} 11 | 12 | private DataAuthorizationProperties dataAuthorizationProperties; 13 | 14 | protected void setDataAuthorizationProperties(DataAuthorizationProperties dataAuthorizationProperties){ 15 | this.dataAuthorizationProperties = dataAuthorizationProperties; 16 | } 17 | 18 | public boolean showSql(){ 19 | if(dataAuthorizationProperties!=null) { 20 | return dataAuthorizationProperties.isShowSql(); 21 | } 22 | return false; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/register/ConditionHandlerRegister.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.register; 2 | 3 | 4 | import com.codingapi.springboot.authorization.handler.RowHandler; 5 | import com.codingapi.springboot.authorization.handler.RowHandlerContext; 6 | 7 | public class ConditionHandlerRegister { 8 | 9 | public ConditionHandlerRegister(RowHandler rowHandler) { 10 | if (rowHandler != null) { 11 | RowHandlerContext.getInstance().setRowHandler(rowHandler); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/register/DataAuthorizationContextRegister.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.register; 2 | 3 | import com.codingapi.springboot.authorization.DataAuthorizationContext; 4 | import com.codingapi.springboot.authorization.filter.DataAuthorizationFilter; 5 | 6 | import java.util.List; 7 | 8 | public class DataAuthorizationContextRegister { 9 | 10 | public DataAuthorizationContextRegister(List dataAuthorizationFilters) { 11 | if(dataAuthorizationFilters!=null) { 12 | for (DataAuthorizationFilter filter : dataAuthorizationFilters) { 13 | DataAuthorizationContext.getInstance().addDataAuthorizationFilter(filter); 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/register/ResultSetHandlerRegister.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.register; 2 | 3 | 4 | import com.codingapi.springboot.authorization.handler.ColumnHandler; 5 | import com.codingapi.springboot.authorization.handler.ColumnHandlerContext; 6 | 7 | public class ResultSetHandlerRegister { 8 | 9 | public ResultSetHandlerRegister(ColumnHandler columnHandler){ 10 | if(columnHandler !=null) { 11 | ColumnHandlerContext.getInstance().setColumnHandler(columnHandler); 12 | } 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/register/SQLInterceptorRegister.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.register; 2 | 3 | 4 | import com.codingapi.springboot.authorization.interceptor.SQLInterceptor; 5 | import com.codingapi.springboot.authorization.interceptor.SQLInterceptorContext; 6 | 7 | public class SQLInterceptorRegister { 8 | 9 | public SQLInterceptorRegister(SQLInterceptor sqlInterceptor) { 10 | if(sqlInterceptor!=null) { 11 | SQLInterceptorContext.getInstance().setSqlInterceptor(sqlInterceptor); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/java/com/codingapi/springboot/authorization/utils/SQLUtils.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.utils; 2 | 3 | import net.sf.jsqlparser.parser.CCJSqlParserUtil; 4 | import net.sf.jsqlparser.statement.Statement; 5 | import net.sf.jsqlparser.statement.select.Select; 6 | 7 | public class SQLUtils { 8 | 9 | /** 10 | * 判断是否为查询 11 | */ 12 | public static boolean isQuerySql(String sql) { 13 | if (sql == null || sql.trim().isEmpty()) { 14 | return false; // 空字符串或 null 不是有效 SQL 15 | } 16 | try { 17 | Statement statement = CCJSqlParserUtil.parse(sql); 18 | return statement instanceof Select; 19 | } catch (Exception e) { 20 | return false; 21 | } 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | com.codingapi.springboot.authorization.DataAuthorizationConfiguration 2 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/test/java/com/codingapi/springboot/authorization/DataAuthorizationTestApplication.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class DataAuthorizationTestApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(DataAuthorizationConfiguration.class,args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/test/java/com/codingapi/springboot/authorization/current/CurrentUser.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.current; 2 | 3 | import com.codingapi.springboot.authorization.entity.User; 4 | import lombok.Getter; 5 | 6 | public class CurrentUser { 7 | 8 | @Getter 9 | private final static CurrentUser instance = new CurrentUser(); 10 | 11 | private final ThreadLocal threadLocal = new ThreadLocal<>(); 12 | 13 | private CurrentUser(){ 14 | } 15 | 16 | public void setUser(User user){ 17 | threadLocal.set(user); 18 | } 19 | 20 | public User getUser(){ 21 | return threadLocal.get(); 22 | } 23 | 24 | public void remove(){ 25 | threadLocal.remove(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/test/java/com/codingapi/springboot/authorization/entity/Depart.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.entity; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.Id; 6 | import jakarta.persistence.Table; 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Setter 12 | @Getter 13 | @Entity 14 | @Table(name = "t_depart") 15 | @NoArgsConstructor 16 | public class Depart { 17 | 18 | @Id 19 | @GeneratedValue 20 | private long id; 21 | 22 | private String name; 23 | 24 | private long parentId; 25 | 26 | private long unitId; 27 | 28 | public Depart(String name, long unitId,long parentId) { 29 | this.name = name; 30 | this.parentId = parentId; 31 | this.unitId = unitId; 32 | } 33 | 34 | public Depart(String name,long unitId) { 35 | this(name,unitId,0); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/test/java/com/codingapi/springboot/authorization/entity/Unit.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.entity; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.Id; 6 | import jakarta.persistence.Table; 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Setter 12 | @Getter 13 | @Entity 14 | @Table(name = "t_unit") 15 | @NoArgsConstructor 16 | public class Unit { 17 | 18 | @Id 19 | @GeneratedValue 20 | private long id; 21 | 22 | private String name; 23 | 24 | private long parentId; 25 | 26 | public Unit(String name, long parentId) { 27 | this.name = name; 28 | this.parentId = parentId; 29 | } 30 | 31 | public Unit(String name) { 32 | this(name,0); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/test/java/com/codingapi/springboot/authorization/mask/impl/BankCardMaskTest.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.mask.impl; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | import static org.junit.jupiter.api.Assertions.assertTrue; 7 | 8 | class BankCardMaskTest { 9 | 10 | @Test 11 | void test() { 12 | String bankCard = "6222021001111111111"; 13 | BankCardMask mask = new BankCardMask(); 14 | assertTrue(mask.support(bankCard)); 15 | assertEquals("622202*********1111", mask.mask(bankCard)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/test/java/com/codingapi/springboot/authorization/mask/impl/IDCardMaskTest.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.mask.impl; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.*; 6 | 7 | class IDCardMaskTest { 8 | 9 | @Test 10 | void test(){ 11 | String idCard = "110101199003074012"; 12 | IDCardMask mask = new IDCardMask(); 13 | assertTrue(mask.support(idCard)); 14 | assertEquals("110101********4012", mask.mask(idCard)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/test/java/com/codingapi/springboot/authorization/mask/impl/PhoneMaskTest.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.mask.impl; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.*; 6 | 7 | class PhoneMaskTest { 8 | 9 | @Test 10 | void test(){ 11 | String phone = "15562581234"; 12 | PhoneMask phoneMask = new PhoneMask(); 13 | assertTrue(phoneMask.support(phone)); 14 | assertEquals("155****1234", phoneMask.mask(phone)); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/test/java/com/codingapi/springboot/authorization/repository/DepartRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.repository; 2 | 3 | import com.codingapi.springboot.authorization.entity.Depart; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface DepartRepository extends JpaRepository { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/test/java/com/codingapi/springboot/authorization/repository/UnitRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.repository; 2 | 3 | import com.codingapi.springboot.authorization.entity.Unit; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface UnitRepository extends JpaRepository { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/test/java/com/codingapi/springboot/authorization/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.authorization.repository; 2 | 3 | import com.codingapi.springboot.authorization.entity.User; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.List; 7 | 8 | public interface UserRepository extends JpaRepository { 9 | 10 | 11 | List findUserByDepartId(long departId); 12 | } 13 | -------------------------------------------------------------------------------- /springboot-starter-data-authorization/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | spring.datasource.driver-class-name=com.codingapi.springboot.authorization.jdbc.AuthorizationJdbcDriver 3 | spring.datasource.url=jdbc:h2:file:./test.db 4 | spring.jpa.database-platform=org.hibernate.dialect.H2Dialect 5 | spring.jpa.hibernate.ddl-auto=create-drop 6 | spring.jpa.show-sql=true 7 | 8 | #spring.datasource.driver-class-name=com.codingapi.springboot.authorization.jdbc.AuthorizationJdbcDriver 9 | #spring.datasource.url=jdbc:mysql://localhost:3306/example?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true 10 | #spring.datasource.username=root 11 | #spring.datasource.password=lorne4j#2024 12 | 13 | logging.level.com.codingapi.springboot.authorization=debug 14 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/jdbc/JdbcQueryConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.jdbc; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.jdbc.core.JdbcTemplate; 6 | 7 | 8 | @Configuration 9 | public class JdbcQueryConfiguration { 10 | 11 | @Bean 12 | public JdbcQuery jdbcQuery(JdbcTemplate jdbcTemplate) { 13 | return new JdbcQuery(jdbcTemplate); 14 | } 15 | 16 | @Bean 17 | public JdbcQueryContextRegister jdbcQueryContextRegister(JdbcQuery jdbcQuery){ 18 | return new JdbcQueryContextRegister(jdbcQuery); 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/jdbc/JdbcQueryContext.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.jdbc; 2 | 3 | 4 | import lombok.Getter; 5 | 6 | public class JdbcQueryContext { 7 | 8 | @Getter 9 | private static final JdbcQueryContext instance = new JdbcQueryContext(); 10 | 11 | private JdbcQueryContext() { 12 | 13 | } 14 | 15 | @Getter 16 | private JdbcQuery jdbcQuery; 17 | 18 | void setJdbcQuery(JdbcQuery jdbcQuery) { 19 | this.jdbcQuery = jdbcQuery; 20 | } 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/jdbc/JdbcQueryContextRegister.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.jdbc; 2 | 3 | import lombok.AllArgsConstructor; 4 | import org.springframework.beans.factory.InitializingBean; 5 | 6 | @AllArgsConstructor 7 | public class JdbcQueryContextRegister implements InitializingBean { 8 | 9 | private JdbcQuery jdbcQuery; 10 | 11 | @Override 12 | public void afterPropertiesSet() throws Exception { 13 | JdbcQueryContext.getInstance().setJdbcQuery(jdbcQuery); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/jpa/JPAQueryConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.jpa; 2 | 3 | import jakarta.persistence.EntityManager; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | 8 | @Configuration 9 | public class JPAQueryConfiguration { 10 | 11 | @Bean 12 | public JPAQuery dynamicQuery(EntityManager entityManager){ 13 | return new JPAQuery(entityManager); 14 | } 15 | 16 | @Bean 17 | public JPAQueryContextRegister jpaQueryContextRegister(JPAQuery JPAQuery){ 18 | return new JPAQueryContextRegister(JPAQuery); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/jpa/JPAQueryContextRegister.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.jpa; 2 | 3 | import lombok.AllArgsConstructor; 4 | import org.springframework.beans.factory.InitializingBean; 5 | 6 | @AllArgsConstructor 7 | public class JPAQueryContextRegister implements InitializingBean { 8 | 9 | private JPAQuery JPAQuery; 10 | 11 | @Override 12 | public void afterPropertiesSet() throws Exception { 13 | JpaQueryContext.getInstance().setJPAQuery(JPAQuery); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/jpa/JpaQueryContext.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.jpa; 2 | 3 | 4 | import lombok.Getter; 5 | 6 | public class JpaQueryContext { 7 | 8 | @Getter 9 | private static final JpaQueryContext instance = new JpaQueryContext(); 10 | 11 | private JpaQueryContext() { 12 | 13 | } 14 | 15 | @Getter 16 | private JPAQuery JPAQuery; 17 | 18 | void setJPAQuery(JPAQuery JPAQuery) { 19 | this.JPAQuery = JPAQuery; 20 | } 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/jpa/repository/BaseRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.jpa.repository; 2 | 3 | import org.springframework.core.ResolvableType; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.repository.NoRepositoryBean; 6 | 7 | @NoRepositoryBean 8 | public interface BaseRepository extends JpaRepository { 9 | 10 | @SuppressWarnings("unchecked") 11 | default Class getEntityClass() { 12 | ResolvableType resolvableType = ResolvableType.forClass(getClass()).as(BaseRepository.class); 13 | return (Class) resolvableType.getGeneric(0).resolve(); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/manager/EntityManagerContent.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.manager; 2 | 3 | import jakarta.persistence.EntityManager; 4 | import lombok.Getter; 5 | 6 | public class EntityManagerContent { 7 | 8 | @Getter 9 | private EntityManager entityManager; 10 | 11 | 12 | private EntityManagerContent() { 13 | } 14 | 15 | 16 | @Getter 17 | private final static EntityManagerContent instance = new EntityManagerContent(); 18 | 19 | 20 | public void push(EntityManager entityManager) { 21 | this.entityManager = entityManager; 22 | } 23 | 24 | 25 | public void detach(Object entity) { 26 | if (entityManager != null) { 27 | entityManager.detach(entity); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/manager/EntityManagerInitializer.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.manager; 2 | 3 | import jakarta.persistence.EntityManager; 4 | import lombok.AllArgsConstructor; 5 | import org.springframework.beans.factory.InitializingBean; 6 | 7 | @AllArgsConstructor 8 | public class EntityManagerInitializer implements InitializingBean { 9 | 10 | private final EntityManager entityManager; 11 | 12 | @Override 13 | public void afterPropertiesSet() throws Exception { 14 | EntityManagerContent.getInstance().push(entityManager); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/main/java/com/codingapi/springboot/fast/script/ScriptMethod.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.script; 2 | 3 | import org.springframework.web.bind.annotation.RequestMethod; 4 | 5 | public enum ScriptMethod { 6 | 7 | GET, POST; 8 | 9 | 10 | public RequestMethod toRequestMethod() { 11 | if (this == GET) { 12 | return RequestMethod.GET; 13 | } else { 14 | return RequestMethod.POST; 15 | } 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | com.codingapi.springboot.fast.DataFastConfiguration,\ 3 | com.codingapi.springboot.fast.jpa.JPAQueryConfiguration,\ 4 | com.codingapi.springboot.fast.jdbc.JdbcQueryConfiguration -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | com.codingapi.springboot.fast.DataFastConfiguration 2 | com.codingapi.springboot.fast.jpa.JPAQueryConfiguration 3 | com.codingapi.springboot.fast.jdbc.JdbcQueryConfiguration -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/DataFastApplication.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class DataFastApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(DataFastApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/entity/Demo.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | @Setter 9 | @Getter 10 | @Entity 11 | @Table(name = "t_demo") 12 | @ToString 13 | public class Demo { 14 | @Id 15 | @GeneratedValue(strategy = GenerationType.IDENTITY) 16 | private Integer id; 17 | 18 | private String name; 19 | 20 | private Integer sort; 21 | } 22 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/entity/Menu.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | 8 | @Setter 9 | @Getter 10 | @Entity 11 | @ToString 12 | public class Menu { 13 | 14 | @Id 15 | @GeneratedValue(strategy = GenerationType.IDENTITY) 16 | private Integer id; 17 | private String name; 18 | 19 | @ManyToOne 20 | private Menu parent; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/entity/Profile.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import jakarta.persistence.*; 7 | 8 | @Entity 9 | @Setter 10 | @Getter 11 | public class Profile { 12 | 13 | @Id 14 | @GeneratedValue(strategy = GenerationType.IDENTITY) 15 | private int id; 16 | 17 | private String name; 18 | 19 | @OneToOne 20 | private Demo demo; 21 | } 22 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import jakarta.persistence.*; 7 | 8 | @Entity 9 | @Setter 10 | @Getter 11 | @Table(name = "t_user") 12 | public class User { 13 | 14 | @Id 15 | @GeneratedValue(strategy = GenerationType.IDENTITY) 16 | private Integer id; 17 | 18 | private String name; 19 | 20 | @OneToOne 21 | private Profile profile; 22 | } 23 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/repository/DemoRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.repository; 2 | 3 | import com.codingapi.springboot.fast.entity.Demo; 4 | import com.codingapi.springboot.fast.jpa.repository.FastRepository; 5 | 6 | public interface DemoRepository extends FastRepository { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/repository/MenuRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.repository; 2 | 3 | import com.codingapi.springboot.fast.entity.Menu; 4 | import com.codingapi.springboot.fast.jpa.repository.FastRepository; 5 | 6 | public interface MenuRepository extends FastRepository { 7 | 8 | 9 | } 10 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/repository/ProfileRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.repository; 2 | 3 | import com.codingapi.springboot.fast.entity.Profile; 4 | import com.codingapi.springboot.fast.jpa.repository.FastRepository; 5 | 6 | public interface ProfileRepository extends FastRepository { 7 | 8 | 9 | } 10 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.repository; 2 | 3 | import com.codingapi.springboot.fast.entity.User; 4 | import com.codingapi.springboot.fast.jpa.repository.FastRepository; 5 | 6 | public interface UserRepository extends FastRepository { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/test/java/com/codingapi/springboot/fast/script/ScriptRuntimeTest.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.fast.script; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertEquals; 7 | 8 | @SpringBootTest 9 | class ScriptRuntimeTest { 10 | 11 | @Test 12 | void running() { 13 | Object res = ScriptRuntime.running("return 1"); 14 | assertEquals(1, res); 15 | } 16 | } -------------------------------------------------------------------------------- /springboot-starter-data-fast/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8088 2 | spring.datasource.driver-class-name=org.h2.Driver 3 | spring.datasource.url=jdbc:h2:file:./test.db 4 | spring.jpa.database-platform=org.hibernate.dialect.H2Dialect 5 | spring.jpa.hibernate.ddl-auto=create-drop 6 | spring.jpa.show-sql=true -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/FlowConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow; 2 | 3 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | public class FlowConfiguration { 10 | 11 | @Bean 12 | @ConditionalOnMissingBean 13 | public FlowFrameworkRegister flowFrameworkRegister(ApplicationContext spring) { 14 | return new FlowFrameworkRegister(spring); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/FlowFrameworkRegister.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow; 2 | 3 | import com.codingapi.springboot.flow.content.FlowSessionBeanProvider; 4 | import lombok.AllArgsConstructor; 5 | import org.springframework.beans.factory.InitializingBean; 6 | import org.springframework.context.ApplicationContext; 7 | 8 | @AllArgsConstructor 9 | public class FlowFrameworkRegister implements InitializingBean { 10 | 11 | private final ApplicationContext application; 12 | 13 | @Override 14 | public void afterPropertiesSet() throws Exception { 15 | FlowSessionBeanProvider.getInstance().register(application); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/bind/IBindData.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.bind; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | 5 | /** 6 | * 数据绑定接口 7 | */ 8 | public interface IBindData { 9 | 10 | String CLASS_NAME_KEY = "clazzName"; 11 | 12 | /** 13 | * 数据快照 14 | * 15 | * @return 数据快照 16 | */ 17 | default String toJsonSnapshot() { 18 | return JSONObject.toJSONString(this); 19 | } 20 | 21 | 22 | /** 23 | * 获取类名称 24 | * 25 | * @return 类名称 26 | */ 27 | default String getClazzName() { 28 | return this.getClass().getName(); 29 | } 30 | 31 | 32 | /** 33 | * 类对象匹配 34 | */ 35 | default boolean match(String dataKey) { 36 | String className = this.getClazzName(); 37 | return dataKey.equals(className); 38 | } 39 | 40 | 41 | /** 42 | * 转化为类对象 43 | */ 44 | default T toJavaObject(Class clazz) { 45 | return (T) this; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/content/FlowSessionBeanProvider.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.content; 2 | 3 | import lombok.Getter; 4 | import org.springframework.context.ApplicationContext; 5 | 6 | /** 7 | * 流程回话 spring bean 提供者 8 | */ 9 | public class FlowSessionBeanProvider { 10 | 11 | @Getter 12 | private static final FlowSessionBeanProvider instance = new FlowSessionBeanProvider(); 13 | 14 | private FlowSessionBeanProvider() { 15 | } 16 | 17 | private ApplicationContext spring; 18 | 19 | public void register(ApplicationContext spring) { 20 | this.spring = spring; 21 | } 22 | 23 | public Object getBean(String beanName) { 24 | if (spring != null) { 25 | return spring.getBean(beanName); 26 | } 27 | return null; 28 | } 29 | 30 | public T getBean(Class clazz) { 31 | if (spring != null) { 32 | return spring.getBean(clazz); 33 | } 34 | return null; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/em/ApprovalType.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.em; 2 | 3 | /** 4 | * 审批类型:会签与非会签 5 | */ 6 | public enum ApprovalType { 7 | 8 | /** 9 | * 会签 10 | */ 11 | SIGN, 12 | /** 13 | * 非会签 14 | */ 15 | UN_SIGN, 16 | /** 17 | * 传阅 18 | */ 19 | CIRCULATE; 20 | 21 | 22 | public static ApprovalType parser(String approvalType) { 23 | for(ApprovalType type:values()){ 24 | if(type.name().equalsIgnoreCase(approvalType)){ 25 | return type; 26 | } 27 | } 28 | return UN_SIGN; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/em/FlowButtonType.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.em; 2 | 3 | public enum FlowButtonType { 4 | 5 | // 保存 6 | SAVE, 7 | // 发起 8 | START, 9 | // 提交 10 | SUBMIT, 11 | // 预提交 12 | TRY_SUBMIT, 13 | // 指定人员提交 14 | SPECIFY_SUBMIT, 15 | // 驳回 16 | REJECT, 17 | // 转办 18 | TRANSFER, 19 | // 撤销 20 | RECALL, 21 | // 延期 22 | POSTPONED, 23 | // 催办 24 | URGE, 25 | // 自定义 26 | CUSTOM, 27 | // 前端 28 | VIEW, 29 | // 删除 30 | REMOVE, 31 | } 32 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/em/FlowSourceDirection.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.em; 2 | 3 | /** 4 | * 流程来源的方式 5 | * 包括 同意、拒绝、转办 6 | */ 7 | public enum FlowSourceDirection { 8 | 9 | /** 10 | * 同意 11 | */ 12 | PASS, 13 | /** 14 | * 拒绝 15 | */ 16 | REJECT, 17 | /** 18 | * 转办 19 | */ 20 | TRANSFER, 21 | /** 22 | * 传阅 23 | */ 24 | CIRCULATE; 25 | 26 | public static FlowSourceDirection parser(String type){ 27 | for(FlowSourceDirection flowSourceDirection :values()){ 28 | if(flowSourceDirection.name().equalsIgnoreCase(type)){ 29 | return flowSourceDirection; 30 | } 31 | } 32 | return null; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/em/FlowStatus.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.em; 2 | 3 | /** 4 | * 流程状态 5 | * 进行中、已完成 6 | */ 7 | public enum FlowStatus { 8 | 9 | /** 10 | * 进行中 11 | */ 12 | RUNNING, 13 | /** 14 | * 已完成 15 | */ 16 | FINISH, 17 | /** 18 | * 已作废 19 | */ 20 | VOIDED; 21 | 22 | 23 | public static FlowStatus parser(String status) { 24 | for (FlowStatus flowStatus : FlowStatus.values()) { 25 | if (flowStatus.name().equalsIgnoreCase(status)) { 26 | return flowStatus; 27 | } 28 | } 29 | return RUNNING; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/em/FlowType.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.em; 2 | 3 | /** 4 | * 流程的类型 5 | */ 6 | public enum FlowType { 7 | 8 | /** 9 | * 待办 10 | */ 11 | TODO, 12 | /** 13 | * 已办 14 | */ 15 | DONE, 16 | /** 17 | * 传阅 18 | */ 19 | CIRCULATE, 20 | /** 21 | * 转办 22 | */ 23 | TRANSFER, 24 | /** 25 | * 等待执行 26 | */ 27 | WAITING, 28 | /** 29 | * 删除 30 | */ 31 | DELETE; 32 | 33 | 34 | public static FlowType parser(String type){ 35 | for(FlowType flowType :values()){ 36 | if(flowType.name().equalsIgnoreCase(type)){ 37 | return flowType; 38 | } 39 | } 40 | return TODO; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/em/NodeType.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.em; 2 | 3 | /** 4 | * 节点类型 5 | */ 6 | public enum NodeType { 7 | 8 | /** 9 | * 发起 10 | */ 11 | START, 12 | /** 13 | * 审批 14 | */ 15 | APPROVAL, 16 | /** 17 | * 传阅 18 | */ 19 | CIRCULATE, 20 | /** 21 | * 结束 22 | */ 23 | OVER; 24 | 25 | 26 | public static NodeType parser(String type) { 27 | for (NodeType nodeType : values()) { 28 | if (nodeType.name().equalsIgnoreCase(type)) { 29 | return nodeType; 30 | } 31 | } 32 | return APPROVAL; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/error/ErrorResult.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.error; 2 | 3 | 4 | /** 5 | * 异常匹配的结果对象 6 | */ 7 | public abstract class ErrorResult { 8 | 9 | public boolean isNode(){ 10 | return this instanceof NodeResult; 11 | } 12 | 13 | public boolean isOperator(){ 14 | return this instanceof OperatorResult; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/error/NodeResult.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.error; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * 节点的异常匹配对象 7 | */ 8 | @Getter 9 | public class NodeResult extends ErrorResult{ 10 | 11 | private final String node; 12 | 13 | public NodeResult(String node) { 14 | this.node = node; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/error/OperatorResult.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.error; 2 | 3 | import lombok.Getter; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | /** 10 | * 操作人员的异常匹配对象 11 | */ 12 | @Getter 13 | public class OperatorResult extends ErrorResult { 14 | 15 | private final List operatorIds; 16 | 17 | public OperatorResult(List operatorIds) { 18 | this.operatorIds = operatorIds; 19 | } 20 | 21 | public OperatorResult(long... operatorIds) { 22 | this.operatorIds = new ArrayList<>(); 23 | Arrays.stream(operatorIds).forEach(this.operatorIds::add); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/pojo/FlowSubmitResult.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.pojo; 2 | 3 | import com.codingapi.springboot.flow.domain.FlowNode; 4 | import com.codingapi.springboot.flow.domain.FlowWork; 5 | import com.codingapi.springboot.flow.user.IFlowOperator; 6 | import lombok.Getter; 7 | 8 | import java.util.List; 9 | 10 | @Getter 11 | public class FlowSubmitResult { 12 | 13 | private final FlowWork flowWork; 14 | private final FlowNode flowNode; 15 | private final List operators; 16 | 17 | public FlowSubmitResult(FlowWork flowWork, FlowNode flowNode, List operators) { 18 | this.flowWork = flowWork; 19 | this.flowNode = flowNode; 20 | this.operators = operators; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/record/FlowMerge.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.record; 2 | 3 | import com.codingapi.springboot.flow.bind.IBindData; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | 7 | @Getter 8 | @AllArgsConstructor 9 | public class FlowMerge { 10 | 11 | private final FlowRecord flowRecord; 12 | private final IBindData bindData; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/repository/FlowBackupRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.repository; 2 | 3 | import com.codingapi.springboot.flow.domain.FlowWork; 4 | import com.codingapi.springboot.flow.record.FlowBackup; 5 | 6 | /** 7 | * 流程备份仓库(流程快照仓库) 8 | */ 9 | public interface FlowBackupRepository { 10 | 11 | /** 12 | * 备份流程 13 | * @param flowWork 流程 14 | * @return 备份对象 15 | */ 16 | FlowBackup backup(FlowWork flowWork); 17 | 18 | /** 19 | * 根据流程id和版本号获取备份 20 | * @param workId 流程id 21 | * @param workVersion 版本号 22 | * @return 备份对象 23 | */ 24 | FlowBackup getFlowBackupByWorkIdAndVersion(long workId,long workVersion); 25 | 26 | /** 27 | * 根据备份id获取备份 28 | * @param backupId 备份id 29 | * @return 备份对象 30 | */ 31 | FlowBackup getFlowBackupById(long backupId); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/repository/FlowBindDataRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.repository; 2 | 3 | import com.codingapi.springboot.flow.bind.BindDataSnapshot; 4 | 5 | /** 6 | * 流程绑定数据仓库 7 | * 流程绑定数据即,流程的表单数据 8 | */ 9 | public interface FlowBindDataRepository { 10 | 11 | /** 12 | * 保存数据 13 | * @param snapshot 数据 14 | */ 15 | void save(BindDataSnapshot snapshot); 16 | 17 | /** 18 | * 更新数据 19 | * @param snapshot 数据 20 | */ 21 | void update(BindDataSnapshot snapshot); 22 | 23 | 24 | /** 25 | * 查询快照数据 26 | * @param id 快照id 27 | * @return BindDataSnapshot 28 | */ 29 | BindDataSnapshot getBindDataSnapshotById(long id); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/repository/FlowOperatorRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.repository; 2 | 3 | import com.codingapi.springboot.flow.user.IFlowOperator; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 流程操作者 仓库 9 | */ 10 | public interface FlowOperatorRepository { 11 | 12 | /** 13 | * 根据ID查询流程用户 14 | * 15 | * @param ids IDs 16 | * @return List of IFlowOperator 17 | */ 18 | List findByIds(List ids); 19 | 20 | 21 | /** 22 | * 根据ID查询流程用户 23 | * 24 | * @param id ID 25 | * @return IFlowOperator 26 | */ 27 | IFlowOperator getFlowOperatorById(long id); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/repository/FlowProcessRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.repository; 2 | 3 | import com.codingapi.springboot.flow.record.FlowProcess; 4 | import com.codingapi.springboot.flow.domain.FlowWork; 5 | 6 | /** 7 | * 流程仓库,每一个流程都会在创建时被创建一条process数据,用于标识流程 8 | */ 9 | public interface FlowProcessRepository { 10 | 11 | void save(FlowProcess flowProcess); 12 | 13 | FlowWork getFlowWorkByProcessId(String processId); 14 | 15 | FlowProcess getFlowProcessByProcessId(String processId); 16 | 17 | void deleteByProcessId(String processId); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/repository/FlowWorkRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.repository; 2 | 3 | import com.codingapi.springboot.flow.domain.FlowWork; 4 | 5 | /** 6 | * 流程设计器仓库 7 | */ 8 | public interface FlowWorkRepository { 9 | 10 | FlowWork getFlowWorkById(long id); 11 | 12 | FlowWork getFlowWorkByCode(String code); 13 | 14 | void save(FlowWork flowWork); 15 | 16 | void delete(long id); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/result/ResultState.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.result; 2 | 3 | /** 4 | * 状态数据 5 | */ 6 | public enum ResultState { 7 | SUCCESS, 8 | INFO, 9 | WARNING; 10 | 11 | 12 | public static ResultState parser(String state) { 13 | if ("SUCCESS".equalsIgnoreCase(state)) { 14 | return SUCCESS; 15 | } else if ("INFO".equalsIgnoreCase(state)) { 16 | return INFO; 17 | } else if ("WARNING".equalsIgnoreCase(state)) { 18 | return WARNING; 19 | } else { 20 | return SUCCESS; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/user/IFlowOperator.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.user; 2 | 3 | /** 4 | * 流程参与用户 5 | */ 6 | public interface IFlowOperator { 7 | 8 | /** 9 | * 获取用户ID 10 | * 11 | * @return ID 12 | */ 13 | long getUserId(); 14 | 15 | 16 | /** 17 | * 获取用户名称 18 | * @return 名称 19 | */ 20 | String getName(); 21 | 22 | 23 | /** 24 | * 是否流程管理员 25 | * 流程管理员可以强制干预流程 26 | */ 27 | boolean isFlowManager(); 28 | 29 | 30 | /** 31 | * 委托操作者 32 | * 当委托操作者不为空时,当前操作者将由委托操作者执行 33 | */ 34 | IFlowOperator entrustOperator(); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/java/com/codingapi/springboot/flow/utils/Sha256Utils.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.utils; 2 | 3 | import java.security.MessageDigest; 4 | import java.security.NoSuchAlgorithmException; 5 | 6 | public class Sha256Utils { 7 | 8 | 9 | public static String generateSHA256(String input) { 10 | try { 11 | MessageDigest digest = MessageDigest.getInstance("SHA-256"); 12 | byte[] hash = digest.digest(input.getBytes()); 13 | StringBuilder hexString = new StringBuilder(); 14 | for (byte b : hash) { 15 | String hex = Integer.toHexString(0xff & b); 16 | if (hex.length() == 1) hexString.append('0'); 17 | hexString.append(hex); 18 | } 19 | return hexString.toString(); 20 | } catch (NoSuchAlgorithmException e) { 21 | throw new RuntimeException(e); 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | com.codingapi.springboot.flow.FlowConfiguration 2 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/test/java/com/codingapi/springboot/flow/FlowTestApplication.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class FlowTestApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(FlowTestApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/test/java/com/codingapi/springboot/flow/flow/Leave.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.flow; 2 | 3 | import com.codingapi.springboot.flow.bind.IBindData; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | 9 | @Setter 10 | @Getter 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | public class Leave implements IBindData { 14 | 15 | private long id; 16 | private String title; 17 | private int days; 18 | 19 | public Leave(String title) { 20 | this(title,0); 21 | } 22 | 23 | public Leave(String title, int days) { 24 | this.title = title; 25 | this.days = days; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/test/java/com/codingapi/springboot/flow/flow/Leave2.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.flow; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Setter 7 | @Getter 8 | public class Leave2 { 9 | 10 | private long id; 11 | private String title; 12 | private int days; 13 | 14 | public Leave2(String title) { 15 | this(title,0); 16 | } 17 | 18 | public Leave2(String title, int days) { 19 | this.title = title; 20 | this.days = days; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /springboot-starter-flow/src/test/java/com/codingapi/springboot/flow/repository/LeaveRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.flow.repository; 2 | 3 | import com.codingapi.springboot.flow.flow.Leave; 4 | import com.codingapi.springboot.flow.flow.Leave2; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class LeaveRepository { 10 | 11 | private final List cache = new ArrayList<>(); 12 | 13 | public void save(Leave leave) { 14 | if (leave.getId() == 0) { 15 | cache.add(leave); 16 | leave.setId(cache.size()); 17 | } 18 | } 19 | 20 | public void save(Leave2 leave2) { 21 | Leave leave = new Leave(leave2.getId(), leave2.getTitle(), leave2.getDays()); 22 | this.save(leave); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/configurer/WebSecurityConfigurer.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.configurer; 2 | 3 | import com.codingapi.springboot.security.properties.CodingApiSecurityProperties; 4 | import lombok.AllArgsConstructor; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.security.config.annotation.web.builders.WebSecurity; 7 | import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; 8 | 9 | @Configuration 10 | @AllArgsConstructor 11 | public class WebSecurityConfigurer implements WebSecurityCustomizer { 12 | 13 | private final CodingApiSecurityProperties securityJwtProperties; 14 | 15 | @Override 16 | public void customize(WebSecurity web) { 17 | //ignoring security filters request url 18 | web.ignoring().requestMatchers(securityJwtProperties.getIgnoreUrls()); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/controller/VersionController.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.controller; 2 | 3 | import com.codingapi.springboot.framework.dto.response.SingleResponse; 4 | import lombok.AllArgsConstructor; 5 | import org.springframework.core.env.Environment; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | @RestController 11 | @RequestMapping("/open") 12 | @AllArgsConstructor 13 | public class VersionController { 14 | 15 | private final Environment env; 16 | 17 | @GetMapping("/version") 18 | public SingleResponse version() { 19 | return SingleResponse.of(env.getProperty("application.version", "-")); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/crypto/SecurityCryptoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.crypto; 2 | 3 | import com.codingapi.springboot.framework.crypto.AES; 4 | import com.codingapi.springboot.security.properties.CodingApiSecurityProperties; 5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | import java.util.Base64; 10 | 11 | @Configuration 12 | public class SecurityCryptoConfiguration { 13 | 14 | @Bean 15 | @ConditionalOnMissingBean 16 | public AES aes(CodingApiSecurityProperties properties) throws Exception { 17 | AES aes = new AES(Base64.getDecoder().decode(properties.getAseKey().getBytes()), 18 | Base64.getDecoder().decode(properties.getAseIv())); 19 | AESTools.getInstance().init(aes); 20 | return aes; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/customer/HttpSecurityCustomer.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.customer; 2 | 3 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 4 | 5 | public interface HttpSecurityCustomer { 6 | 7 | void customize(HttpSecurity security) throws Exception; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/dto/request/LoginRequest.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.dto.request; 2 | 3 | import lombok.ToString; 4 | 5 | import java.util.HashMap; 6 | 7 | @ToString 8 | public class LoginRequest extends HashMap { 9 | 10 | public boolean isEmpty() { 11 | return getPassword() == null || getUsername() == null; 12 | } 13 | 14 | public String getPassword() { 15 | return getString("password"); 16 | } 17 | 18 | public String getUsername() { 19 | return getString("username"); 20 | } 21 | 22 | public boolean getBoolean(String key, boolean defaultValue) { 23 | try { 24 | return (boolean) get(key); 25 | } catch (Exception e) { 26 | return defaultValue; 27 | } 28 | } 29 | 30 | public String getString(String key) { 31 | return (String) get(key); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/dto/request/LoginRequestContext.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.dto.request; 2 | 3 | public class LoginRequestContext { 4 | 5 | private static LoginRequestContext context = new LoginRequestContext(); 6 | private final ThreadLocal threadLocal = new ThreadLocal<>(); 7 | 8 | private LoginRequestContext() { 9 | 10 | } 11 | 12 | public static LoginRequestContext getInstance() { 13 | return context; 14 | } 15 | 16 | public void set(LoginRequest request) { 17 | threadLocal.set(request); 18 | } 19 | 20 | public LoginRequest get() { 21 | return threadLocal.get(); 22 | } 23 | 24 | public void clean() { 25 | threadLocal.set(null); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/dto/response/LoginResponse.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.dto.response; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import java.util.List; 7 | 8 | @Setter 9 | @Getter 10 | public class LoginResponse { 11 | private String username; 12 | private String token; 13 | private List authorities; 14 | private Object data; 15 | } 16 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/exception/TokenExpiredException.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.exception; 2 | 3 | public class TokenExpiredException extends Exception { 4 | 5 | public TokenExpiredException(String message) { 6 | super(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/filter/AuthenticationTokenFilter.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.filter; 2 | 3 | import jakarta.servlet.ServletException; 4 | import jakarta.servlet.http.HttpServletRequest; 5 | import jakarta.servlet.http.HttpServletResponse; 6 | 7 | import java.io.IOException; 8 | 9 | public interface AuthenticationTokenFilter { 10 | 11 | void doFilter(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/filter/MyLogoutHandler.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.filter; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.security.core.Authentication; 5 | import org.springframework.security.web.authentication.logout.LogoutHandler; 6 | 7 | import jakarta.servlet.http.HttpServletRequest; 8 | import jakarta.servlet.http.HttpServletResponse; 9 | 10 | @Slf4j 11 | public class MyLogoutHandler implements LogoutHandler { 12 | 13 | @Override 14 | public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { 15 | log.debug("logout ~ "); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/filter/SecurityLoginHandler.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.filter; 2 | 3 | import com.codingapi.springboot.security.dto.request.LoginRequest; 4 | import com.codingapi.springboot.security.dto.response.LoginResponse; 5 | import com.codingapi.springboot.security.gateway.Token; 6 | import jakarta.servlet.http.HttpServletRequest; 7 | import jakarta.servlet.http.HttpServletResponse; 8 | import org.springframework.security.core.userdetails.User; 9 | import org.springframework.security.core.userdetails.UserDetails; 10 | 11 | public interface SecurityLoginHandler { 12 | 13 | void preHandle(HttpServletRequest request, HttpServletResponse response, LoginRequest loginRequest) throws Exception; 14 | 15 | LoginResponse postHandle(HttpServletRequest request, HttpServletResponse response, LoginRequest loginRequest, UserDetails user, Token token); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/gateway/TokenContext.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.gateway; 2 | 3 | import org.springframework.security.core.context.SecurityContextHolder; 4 | 5 | public class TokenContext { 6 | 7 | private static final ThreadLocal threadLocal = new ThreadLocal<>(); 8 | 9 | private TokenContext() { 10 | } 11 | 12 | public static Token current() { 13 | return (Token) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 14 | } 15 | 16 | public static void pushExtra(String extra){ 17 | threadLocal.set(extra); 18 | } 19 | 20 | public static String getExtra(){ 21 | return threadLocal.get(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/gateway/TokenGateway.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.gateway; 2 | 3 | import java.util.List; 4 | 5 | public interface TokenGateway { 6 | 7 | Token create(String username, String iv, List authorities, String extra); 8 | 9 | default Token create(String username, String iv, List authorities) { 10 | return create(username, iv, authorities, null); 11 | } 12 | 13 | default Token create(String username, List authorities) { 14 | return create(username, null, authorities, null); 15 | } 16 | 17 | default Token create(String username, List authorities, String extra) { 18 | return create(username, null, authorities, extra); 19 | } 20 | 21 | Token parser(String sign); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/jwt/JWTTokenGatewayImpl.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.jwt; 2 | 3 | import com.codingapi.springboot.security.gateway.Token; 4 | import com.codingapi.springboot.security.gateway.TokenGateway; 5 | 6 | import java.util.List; 7 | 8 | public class JWTTokenGatewayImpl implements TokenGateway { 9 | 10 | private final JwtTokenGateway jwtTokenGateway; 11 | 12 | public JWTTokenGatewayImpl(JwtTokenGateway jwtTokenGateway) { 13 | this.jwtTokenGateway = jwtTokenGateway; 14 | } 15 | 16 | @Override 17 | public Token create(String username, String password, List authorities, String extra) { 18 | return jwtTokenGateway.create(username, password, authorities, extra); 19 | } 20 | 21 | @Override 22 | public Token parser(String sign) { 23 | return jwtTokenGateway.parser(sign); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/jwt/SecurityJWTProperties.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.jwt; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Setter 7 | @Getter 8 | public class SecurityJWTProperties { 9 | 10 | 11 | /** 12 | * 是否启用JWT 13 | */ 14 | private boolean enable = true; 15 | 16 | /** 17 | * JWT密钥 18 | * 需大于32位的字符串 19 | */ 20 | private String secretKey = "codingapi.security.jwt.secretkey"; 21 | 22 | 23 | /** 24 | * JWT 有效时间(毫秒) 25 | * 15分钟有效期 1000*60*15=900000 26 | */ 27 | private int validTime = 900000; 28 | 29 | /** 30 | * JWT 更换令牌时间(毫秒) 31 | * 10分钟后更换令牌 1000*60*10=600000 32 | */ 33 | private int restTime = 600000; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/redis/RedisTokenGatewayImpl.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.redis; 2 | 3 | import com.codingapi.springboot.security.gateway.Token; 4 | import com.codingapi.springboot.security.gateway.TokenGateway; 5 | 6 | import java.util.List; 7 | 8 | public class RedisTokenGatewayImpl implements TokenGateway { 9 | 10 | private final RedisTokenGateway redisTokenGateway; 11 | 12 | public RedisTokenGatewayImpl(RedisTokenGateway redisTokenGateway) { 13 | this.redisTokenGateway = redisTokenGateway; 14 | } 15 | 16 | @Override 17 | public Token create(String username, String iv, List authorities, String extra) { 18 | return redisTokenGateway.create(username, iv, authorities, extra); 19 | } 20 | 21 | @Override 22 | public Token parser(String sign) { 23 | return redisTokenGateway.getToken(sign); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/java/com/codingapi/springboot/security/redis/SecurityRedisProperties.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.redis; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Setter 7 | @Getter 8 | public class SecurityRedisProperties { 9 | 10 | 11 | /** 12 | * 是否启用redis 13 | */ 14 | private boolean enable = true; 15 | 16 | /** 17 | * 15分钟有效期 1000*60*15=900000 18 | */ 19 | private int validTime = 900000; 20 | 21 | /** 22 | * 10分钟后更换令牌 1000*60*10=600000 23 | */ 24 | private int restTime = 600000; 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /springboot-starter-security/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | com.codingapi.springboot.security.configurer.WebSecurityConfigurer,\ 3 | com.codingapi.springboot.security.jwt.JWTSecurityConfiguration,\ 4 | com.codingapi.springboot.security.redis.RedisSecurityConfiguration,\ 5 | com.codingapi.springboot.security.crypto.SecurityCryptoConfiguration,\ 6 | com.codingapi.springboot.security.AutoConfiguration -------------------------------------------------------------------------------- /springboot-starter-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | com.codingapi.springboot.security.configurer.WebSecurityConfigurer 2 | com.codingapi.springboot.security.crypto.SecurityCryptoConfiguration 3 | com.codingapi.springboot.security.jwt.JWTSecurityConfiguration 4 | com.codingapi.springboot.security.redis.RedisSecurityConfiguration 5 | com.codingapi.springboot.security.AutoConfiguration -------------------------------------------------------------------------------- /springboot-starter-security/src/test/java/com/codingapi/springboot/security/controller/DemoController.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.controller; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | @RequestMapping("/api") 9 | public class DemoController { 10 | 11 | @GetMapping("/hello") 12 | public String hello(){ 13 | return "hello"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /springboot-starter-security/src/test/java/com/codingapi/springboot/security/jwt/TestVO.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.security.jwt; 2 | 3 | import com.codingapi.springboot.framework.serializable.JsonSerializable; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | 9 | @Setter 10 | @Getter 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | public class TestVO implements JsonSerializable { 14 | 15 | private String name; 16 | } 17 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/AutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | 5 | @Configuration 6 | public class AutoConfiguration { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/annotation/ColumnType.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.annotation; 2 | 3 | /** 4 | * 数据库字段类型 5 | */ 6 | public enum ColumnType { 7 | 8 | /** 9 | * 整数 10 | */ 11 | Number, 12 | 13 | /** 14 | * 浮点数 15 | */ 16 | Float, 17 | 18 | /** 19 | * 字符串 20 | */ 21 | String, 22 | 23 | /** 24 | * 日期 25 | */ 26 | Date, 27 | 28 | /** 29 | * 文件 30 | */ 31 | File, 32 | 33 | /** 34 | * 布尔 35 | */ 36 | Boolean, 37 | 38 | /** 39 | * 字节 40 | */ 41 | Bytes, 42 | 43 | /** 44 | * JSON 45 | */ 46 | JSON, 47 | 48 | /** 49 | * 任意 50 | */ 51 | Any 52 | } 53 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/annotation/MetaColumn.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 查询字段 7 | */ 8 | @Target({ElementType.FIELD}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Documented 11 | public @interface MetaColumn { 12 | 13 | /** 14 | * 字段说明 15 | */ 16 | String desc(); 17 | 18 | /** 19 | * 字段名称 20 | */ 21 | String name(); 22 | 23 | /** 24 | * 是否主键 25 | */ 26 | boolean primaryKey() default false; 27 | 28 | /** 29 | * 字段类型 30 | */ 31 | ColumnType type() default ColumnType.String; 32 | 33 | /** 34 | * 格式化 35 | */ 36 | String format() default ""; 37 | 38 | /** 39 | * 依赖表 40 | */ 41 | MetaRelation dependent() default @MetaRelation(tableName = "", columnName = ""); 42 | 43 | } 44 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/annotation/MetaRelation.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | 7 | @Retention(RetentionPolicy.RUNTIME) 8 | @Documented 9 | public @interface MetaRelation { 10 | 11 | /** 12 | * 表名称 13 | */ 14 | String tableName(); 15 | 16 | /** 17 | * 字段名称 18 | */ 19 | String columnName(); 20 | } 21 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/annotation/MetaTable.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 查询表 7 | */ 8 | @Target({ElementType.TYPE}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Documented 11 | public @interface MetaTable { 12 | 13 | /** 14 | * 表说明 15 | */ 16 | String desc(); 17 | 18 | /** 19 | * 表名称 20 | */ 21 | String name(); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/command/IExecutor.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.command; 2 | 3 | import com.codingapi.springboot.framework.dto.response.Response; 4 | 5 | public interface IExecutor { 6 | 7 | interface Command { 8 | R execute(C command); 9 | } 10 | 11 | interface Void { 12 | R execute(); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/convert/BeanConvertor.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.convert; 2 | 3 | import org.springframework.beans.BeanUtils; 4 | 5 | import java.lang.reflect.InvocationTargetException; 6 | 7 | public class BeanConvertor { 8 | 9 | public static T convert(S source, Class clazz) { 10 | if (source == null) { 11 | return null; 12 | } 13 | T target = null; 14 | try { 15 | target = clazz.getDeclaredConstructor().newInstance(); 16 | } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | 17 | InvocationTargetException e) { 18 | return null; 19 | } 20 | BeanUtils.copyProperties(source, target); 21 | return target; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/crypto/HmacSHA256.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.crypto; 2 | 3 | import javax.crypto.Mac; 4 | import javax.crypto.spec.SecretKeySpec; 5 | import java.security.InvalidKeyException; 6 | import java.security.NoSuchAlgorithmException; 7 | 8 | public class HmacSHA256 { 9 | 10 | public static byte[] sha256(byte[] message,byte[] secret) throws NoSuchAlgorithmException, InvalidKeyException { 11 | Mac sha256_HMAC = Mac.getInstance("HmacSha256"); 12 | SecretKeySpec secretKey = new SecretKeySpec(secret,"HmacSha256"); 13 | sha256_HMAC.init(secretKey); 14 | return sha256_HMAC.doFinal(message); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/domain/IDomain.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.domain; 2 | 3 | import com.codingapi.springboot.framework.domain.event.DomainDeleteEvent; 4 | import com.codingapi.springboot.framework.domain.event.DomainPersistEvent; 5 | import com.codingapi.springboot.framework.event.EventPusher; 6 | 7 | /** 8 | * 领域对象事件 9 | */ 10 | public interface IDomain { 11 | 12 | /** 13 | * 持久化事件 14 | */ 15 | default void persist(){ 16 | EventPusher.push(new DomainPersistEvent(this)); 17 | } 18 | 19 | /** 20 | * 删除事件 21 | */ 22 | default void delete(){ 23 | EventPusher.push(new DomainDeleteEvent(this)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/domain/ISort.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.domain; 2 | 3 | public interface ISort { 4 | 5 | void setSort(Integer sort); 6 | 7 | Integer getSort(); 8 | } 9 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/domain/event/DomainChangeEvent.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.domain.event; 2 | 3 | import lombok.Getter; 4 | import lombok.ToString; 5 | 6 | /** 7 | * 实体字段变更事件 8 | */ 9 | @Getter 10 | @ToString(callSuper = true) 11 | public class DomainChangeEvent extends DomainEvent { 12 | 13 | /** 14 | * 字段名称 15 | */ 16 | private final String fieldName; 17 | /** 18 | * 旧的值 19 | */ 20 | private final Object oldValue; 21 | /** 22 | * 新的值 23 | */ 24 | private final Object newValue; 25 | 26 | public DomainChangeEvent(Object entity, String fieldName, Object oldValue, Object newValue) { 27 | super(entity); 28 | this.fieldName = fieldName; 29 | this.oldValue = oldValue; 30 | this.newValue = newValue; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/domain/event/DomainCreateEvent.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.domain.event; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * 实体创建事件 7 | */ 8 | @Getter 9 | public class DomainCreateEvent extends DomainEvent { 10 | 11 | public DomainCreateEvent(Object entity) { 12 | super(entity); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/domain/event/DomainDeleteEvent.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.domain.event; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * 实体删除事件 7 | */ 8 | @Getter 9 | public class DomainDeleteEvent extends DomainEvent { 10 | 11 | public DomainDeleteEvent(Object entity) { 12 | super(entity); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/domain/event/DomainEvent.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.domain.event; 2 | 3 | import com.codingapi.springboot.framework.event.IEvent; 4 | import lombok.Getter; 5 | import lombok.ToString; 6 | 7 | /** 8 | * 实体事件 9 | */ 10 | @Getter 11 | @ToString(exclude = "entity") 12 | public abstract class DomainEvent implements IEvent { 13 | 14 | /** 15 | * 实体类型 16 | */ 17 | private final Class entityClass; 18 | /** 19 | * 时间戳 20 | */ 21 | private final long timestamp; 22 | /** 23 | * 实体 24 | */ 25 | private final Object entity; 26 | 27 | public DomainEvent(Object entity) { 28 | this.entity = entity; 29 | this.entityClass = entity.getClass(); 30 | this.timestamp = System.currentTimeMillis(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/domain/event/DomainPersistEvent.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.domain.event; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * 实体持久化事件 7 | */ 8 | @Getter 9 | public class DomainPersistEvent extends DomainEvent { 10 | 11 | public DomainPersistEvent(Object entity) { 12 | super(entity); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/dto/request/IdRequest.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.dto.request; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Setter 7 | @Getter 8 | public class IdRequest { 9 | 10 | private String id; 11 | 12 | public String getStringId(){ 13 | return id; 14 | } 15 | 16 | public int getIntId(){ 17 | return Integer.parseInt(id); 18 | } 19 | 20 | public Long getLongId(){ 21 | return Long.parseLong(id); 22 | } 23 | 24 | public float getFloatId(){ 25 | return Float.parseFloat(id); 26 | } 27 | 28 | public double getDoubleId(){ 29 | return Double.parseDouble(id); 30 | } 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/dto/request/Relation.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.dto.request; 2 | 3 | public enum Relation { 4 | 5 | EQUAL, 6 | NOT_EQUAL, 7 | LIKE, 8 | LEFT_LIKE, 9 | RIGHT_LIKE, 10 | BETWEEN, 11 | IN, 12 | NOT_IN, 13 | IS_NULL, 14 | IS_NOT_NULL, 15 | GREATER_THAN, 16 | LESS_THAN, 17 | GREATER_THAN_EQUAL, 18 | LESS_THAN_EQUAL, 19 | } 20 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/dto/request/SortRequest.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.dto.request; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import java.util.List; 7 | 8 | @Setter 9 | @Getter 10 | public class SortRequest { 11 | 12 | private List ids; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/dto/response/Response.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.dto.response; 2 | 3 | import com.codingapi.springboot.framework.serializable.JsonSerializable; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | /** 8 | * @author lorne 9 | * 2020/12/17 10 | */ 11 | @Setter 12 | @Getter 13 | public class Response implements JsonSerializable { 14 | 15 | private boolean success; 16 | 17 | private String errCode; 18 | 19 | private String errMessage; 20 | 21 | public static Response buildFailure(String errCode, String errMessage) { 22 | Response response = new Response(); 23 | response.setSuccess(false); 24 | response.setErrCode(errCode); 25 | response.setErrMessage(errMessage); 26 | return response; 27 | } 28 | 29 | public static Response buildSuccess() { 30 | Response response = new Response(); 31 | response.setSuccess(true); 32 | return response; 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/dto/response/SingleResponse.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.dto.response; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | /** 7 | * @author lorne 8 | * 2020/12/17 9 | */ 10 | @Setter 11 | @Getter 12 | public class SingleResponse extends Response { 13 | 14 | private T data; 15 | 16 | public static SingleResponse of(T data) { 17 | SingleResponse singleResponse = new SingleResponse<>(); 18 | singleResponse.setSuccess(true); 19 | singleResponse.setData(data); 20 | return singleResponse; 21 | } 22 | 23 | 24 | public static SingleResponse empty() { 25 | SingleResponse singleResponse = new SingleResponse<>(); 26 | singleResponse.setSuccess(true); 27 | singleResponse.setData(null); 28 | return singleResponse; 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/em/IEnum.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.em; 2 | 3 | public interface IEnum { 4 | 5 | int getCode(); 6 | } 7 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/event/DomainEvent.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.event; 2 | 3 | import lombok.Getter; 4 | import org.springframework.context.ApplicationEvent; 5 | 6 | /** 7 | * Event包装对象 8 | */ 9 | public class DomainEvent extends ApplicationEvent { 10 | 11 | @Getter 12 | private final IEvent event; 13 | /** 14 | * 同步或异步事件 15 | * true 同步 16 | * false 异步 17 | */ 18 | @Getter 19 | private final boolean sync; 20 | 21 | @Getter 22 | private final String traceId; 23 | 24 | 25 | public DomainEvent(Object source, boolean sync, String traceId) { 26 | super(source); 27 | this.event = (IEvent) source; 28 | this.sync = sync; 29 | this.traceId = traceId; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/event/EventPusher.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.event; 2 | 3 | /** 4 | * Even推送助手 5 | */ 6 | public class EventPusher { 7 | 8 | /** 9 | * 推送事件 10 | * 默认将自动检测事件是否有循环事件,当出现循环事件时,系统将会抛出循环调用异常。 11 | * @param event 事件 12 | */ 13 | public static void push(IEvent event) { 14 | push(event, false); 15 | } 16 | 17 | /** 18 | * 推送事件 19 | * 默认将自动检测事件是否有循环事件,当出现循环事件时,系统将会抛出循环调用异常。 20 | * 设置hasLoopEvent为true,将不会检测循环事件。 21 | * @param event 事件 22 | * @param hasLoopEvent 是否有循环事件 23 | */ 24 | public static void push(IEvent event, boolean hasLoopEvent) { 25 | DomainEventContext.getInstance().push(event, hasLoopEvent); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/event/Handler.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.event; 2 | 3 | import java.lang.annotation.*; 4 | 5 | 6 | /** 7 | * handler bean 注解 8 | */ 9 | @Target({ElementType.TYPE}) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | @Documented 12 | public @interface Handler { 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/event/IAsyncEvent.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.event; 2 | 3 | /** 4 | * 异步事件 5 | */ 6 | public interface IAsyncEvent extends IEvent { 7 | 8 | 9 | } 10 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/event/IEvent.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.event; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | /** 7 | * 默认同步事件 8 | *

9 | * 关于事件与事务之间的关系说明: 10 | * 事件本身不应该同步主业务的事务,即事件对于主业务来说,可成功可失败,成功与失败都不应该强关联主体业务。 11 | * 若需要让主体业务与分支做事务同步的时候,那不应该采用事件机制,而应该直接采用调用的方式实现业务绑定。 12 | */ 13 | public interface IEvent extends Serializable { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/event/IHandler.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.event; 2 | 3 | /** 4 | * handler 订阅 5 | * 6 | * @param Event 类型 7 | */ 8 | public interface IHandler { 9 | 10 | /** 11 | * 事件订阅排序 12 | * 在同样的事件中,可以通过order来控制订阅的顺序 13 | */ 14 | default int order() { 15 | return 0; 16 | } 17 | 18 | /** 19 | * 订阅触发 20 | * 21 | * @param event 触发event 22 | */ 23 | void handler(T event); 24 | 25 | /** 26 | * 异常回掉,在多订阅的情况下,为了实现订阅的独立性,将异常的处理放在回掉函数中。 27 | * 当异常抛出以后,会阻止后续的事件执行 28 | * 29 | * @param exception 异常信息 30 | */ 31 | default void error(Exception exception) throws Exception { 32 | throw exception; 33 | } 34 | 35 | 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/event/ISyncEvent.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.event; 2 | 3 | /** 4 | * 同步事件 5 | */ 6 | public interface ISyncEvent extends IEvent { 7 | 8 | 9 | } 10 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/event/SpringEventConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.event; 2 | 3 | import org.springframework.context.ApplicationContext; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @Configuration 8 | public class SpringEventConfiguration { 9 | 10 | @Bean 11 | public SpringEventInitializer springEventInitializer(ApplicationContext context) { 12 | return new SpringEventInitializer(context); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/event/SpringEventInitializer.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.event; 2 | 3 | import lombok.AllArgsConstructor; 4 | import org.springframework.beans.factory.InitializingBean; 5 | import org.springframework.context.ApplicationContext; 6 | 7 | @AllArgsConstructor 8 | public class SpringEventInitializer implements InitializingBean { 9 | 10 | private final ApplicationContext context; 11 | 12 | @Override 13 | public void afterPropertiesSet() throws Exception { 14 | DomainEventContext.getInstance().initContext(context); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/event/SpringHandlerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.event; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | import java.util.List; 8 | 9 | @Configuration 10 | public class SpringHandlerConfiguration { 11 | 12 | @Bean 13 | public SpringEventHandler springEventHandler(@Autowired(required = false) List handlers) { 14 | return new SpringEventHandler(handlers); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/exception/EventException.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.exception; 2 | 3 | import lombok.Getter; 4 | 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | 8 | @Getter 9 | public class EventException extends RuntimeException { 10 | 11 | private final List error; 12 | 13 | public EventException(List error) { 14 | super(error.stream().map(Exception::getMessage).collect(Collectors.joining("\n"))); 15 | this.error = error; 16 | for (Exception e : error) { 17 | e.printStackTrace(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/exception/EventLoopException.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.exception; 2 | 3 | import com.codingapi.springboot.framework.event.IEvent; 4 | import lombok.Getter; 5 | 6 | import java.util.List; 7 | 8 | @Getter 9 | public class EventLoopException extends RuntimeException { 10 | 11 | private final List> stack; 12 | 13 | public EventLoopException(List> stack, IEvent event) { 14 | super("event loop error current event class:" + event.getClass() + ", history event stack:" + stack); 15 | this.stack = stack; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/exception/ExceptionConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.exception; 2 | 3 | import org.springframework.context.MessageSource; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @Configuration 8 | public class ExceptionConfiguration { 9 | 10 | @Bean(initMethod = "init") 11 | public LocaleMessage exceptionLocaleMessage(MessageSource messageSource) { 12 | return new LocaleMessage(messageSource); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/exception/MessageContext.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.exception; 2 | 3 | 4 | class MessageContext { 5 | 6 | private static MessageContext context; 7 | private LocaleMessage localeMessage; 8 | 9 | private MessageContext() { 10 | 11 | } 12 | 13 | public static MessageContext getInstance() { 14 | if (context == null) { 15 | synchronized (MessageContext.class) { 16 | context = new MessageContext(); 17 | } 18 | } 19 | return context; 20 | } 21 | 22 | void setExceptionLocaleMessage(LocaleMessage localeMessage) { 23 | this.localeMessage = localeMessage; 24 | } 25 | 26 | public String getErrorMsg(String errCode) { 27 | return localeMessage.getMessage(errCode); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/rest/Request.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.rest; 2 | 3 | public interface Request { 4 | 5 | String execute(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/rest/param/IRestParam.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.rest.param; 2 | 3 | public interface IRestParam { 4 | 5 | default RestParam toParameters() { 6 | return RestParam.parser(this); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/rest/properties/HttpProxyProperties.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.rest.properties; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import java.net.Proxy; 7 | 8 | @Setter 9 | @Getter 10 | public class HttpProxyProperties { 11 | 12 | private boolean enableProxy; 13 | private String proxyHost; 14 | private int proxyPort; 15 | private Proxy.Type proxyType; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/serializable/EnumSerializer.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.serializable; 2 | 3 | import com.codingapi.springboot.framework.em.IEnum; 4 | import com.fasterxml.jackson.core.JsonGenerator; 5 | import com.fasterxml.jackson.databind.JsonSerializer; 6 | import com.fasterxml.jackson.databind.SerializerProvider; 7 | 8 | import java.io.IOException; 9 | 10 | public class EnumSerializer extends JsonSerializer { 11 | 12 | @Override 13 | public void serialize(IEnum iEnum, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { 14 | jsonGenerator.writeNumber(iEnum.getCode()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/serializable/JsonSerializable.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.serializable; 2 | 3 | 4 | import com.alibaba.fastjson.JSONObject; 5 | 6 | import java.io.Serializable; 7 | 8 | public interface JsonSerializable extends Serializable { 9 | 10 | default String toJson() { 11 | return JSONObject.toJSONString(this); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/serializable/MapSerializable.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.serializable; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * @author lorne 9 | * @since 1.0.0 10 | */ 11 | public interface MapSerializable { 12 | 13 | default Map toMap() { 14 | return JSON.parseObject(JSON.toJSONString(this)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/trigger/Trigger.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.trigger; 2 | 3 | /** 4 | * 触发的DTO对象 5 | */ 6 | public interface Trigger { 7 | } 8 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/trigger/TriggerHandler.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.trigger; 2 | 3 | 4 | /** 5 | * 触发逻辑 6 | * @param 触发DTO对象 {@link Trigger} 7 | */ 8 | public interface TriggerHandler { 9 | 10 | /** 11 | * 是否进入触发器 12 | * @param trigger 触发对象 {@link Trigger} 13 | * @return true进入 false 不进入 14 | */ 15 | boolean preTrigger(T trigger); 16 | 17 | /** 18 | * 触发执行逻辑 19 | * @param trigger 触发对象 {@link Trigger} 20 | */ 21 | void trigger(T trigger); 22 | 23 | /** 24 | * 执行完成以后是否删除触发器 25 | * @param trigger 触发对象 {@link Trigger} 26 | * @param canTrigger 是否执行过程trigger逻辑 true执行过程 false未执行 27 | * @return true删除 28 | */ 29 | default boolean remove(T trigger, boolean canTrigger){ 30 | return false; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/utils/FullDateFormatUtils.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.utils; 2 | 3 | 4 | import java.text.SimpleDateFormat; 5 | import java.util.Date; 6 | import java.util.TimeZone; 7 | 8 | public class FullDateFormatUtils { 9 | private final static SimpleDateFormat defaultFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 10 | 11 | static { 12 | defaultFormat.setTimeZone(TimeZone.getTimeZone("GMT+8:00")); 13 | } 14 | 15 | public static String convert(long timestamp){ 16 | return convert(new Date(timestamp)); 17 | } 18 | 19 | public static String convert(Date date){ 20 | return defaultFormat.format(date); 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /springboot-starter/src/main/java/com/codingapi/springboot/framework/utils/RandomGenerator.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.utils; 2 | 3 | import java.util.UUID; 4 | 5 | public class RandomGenerator { 6 | 7 | public static String generateUUID() { 8 | return UUID.randomUUID().toString(); 9 | } 10 | 11 | 12 | public static String randomString(int length) { 13 | String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 14 | StringBuilder sb = new StringBuilder(); 15 | for (int i = 0; i < length; i++) { 16 | int number = (int) (Math.random() * str.length()); 17 | sb.append(str.charAt(number)); 18 | } 19 | return sb.toString(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /springboot-starter/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | com.codingapi.springboot.framework.AutoConfiguration,\ 3 | com.codingapi.springboot.framework.event.SpringEventConfiguration,\ 4 | com.codingapi.springboot.framework.exception.ExceptionConfiguration,\ 5 | com.codingapi.springboot.framework.event.HandlerBeanDefinitionRegistrar,\ 6 | com.codingapi.springboot.framework.event.SpringHandlerConfiguration,\ 7 | com.codingapi.springboot.framework.servlet.BasicHandlerExceptionResolverConfiguration 8 | -------------------------------------------------------------------------------- /springboot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | com.codingapi.springboot.framework.AutoConfiguration 2 | com.codingapi.springboot.framework.event.SpringEventConfiguration 3 | com.codingapi.springboot.framework.exception.ExceptionConfiguration 4 | com.codingapi.springboot.framework.event.HandlerBeanDefinitionRegistrar 5 | com.codingapi.springboot.framework.event.SpringHandlerConfiguration 6 | com.codingapi.springboot.framework.servlet.BasicHandlerExceptionResolverConfiguration 7 | -------------------------------------------------------------------------------- /springboot-starter/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------ 2 | CodingApi SpringBoot-Starter 3.4.8 3 | springboot version (${spring-boot.version}) 4 | ------------------------------------------------------ 5 | -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/FrameWorkApplication.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework; 2 | 3 | import com.codingapi.springboot.framework.boot.DynamicApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class FrameWorkApplication { 8 | 9 | public static void main(String[] args) { 10 | DynamicApplication.run(FrameWorkApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/controller/DemoController.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.controller; 2 | 3 | import com.codingapi.springboot.framework.dto.response.MapResponse; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | @RequestMapping("/open") 10 | public class DemoController { 11 | 12 | @GetMapping("/hello") 13 | public MapResponse hello(){ 14 | return MapResponse.create().add("hello","hello"); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/crypto/DESTest.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.crypto; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.security.NoSuchAlgorithmException; 6 | 7 | import static org.junit.jupiter.api.Assertions.*; 8 | 9 | class DESTest { 10 | 11 | @Test 12 | void getKey() throws NoSuchAlgorithmException { 13 | DES des = new DES(); 14 | byte[] key = des.getKey(); 15 | assertNotNull(key); 16 | } 17 | 18 | @Test 19 | void encryptAndDecrypt() throws Exception { 20 | DES des = new DES(); 21 | String word = "123"; 22 | byte[] encrypt = des.encrypt(word.getBytes()); 23 | byte[] decrypt = des.decrypt(encrypt); 24 | assertEquals(word,new String(decrypt)); 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/crypto/HmacSHA256Test.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.crypto; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.security.InvalidKeyException; 6 | import java.security.NoSuchAlgorithmException; 7 | import java.util.Base64; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertEquals; 10 | 11 | class HmacSHA256Test { 12 | 13 | @Test 14 | void sha256() throws NoSuchAlgorithmException, InvalidKeyException { 15 | String data = Base64.getEncoder().encodeToString(HmacSHA256.sha256("123456".getBytes(),"123456".getBytes())); 16 | assertEquals("uK0Io6VH41gpuCG3U3AwHdjEsGvdd3H5tUGnWRQGhxg=",data); 17 | } 18 | } -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/domain/Animal.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.domain; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Setter 7 | @Getter 8 | public class Animal { 9 | 10 | private String name; 11 | } 12 | -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/domain/DemoEntity.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.domain; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Setter 7 | @Getter 8 | public class DemoEntity { 9 | 10 | private Integer id; 11 | private String name; 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/domain/DomainProxyFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.domain; 2 | 3 | import com.codingapi.springboot.framework.domain.proxy.DomainProxyFactory; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | 7 | @SpringBootTest 8 | class DomainProxyFactoryTest { 9 | 10 | @Test 11 | void createEntity() { 12 | Demo demo = DomainProxyFactory.create(Demo.class, "test"); 13 | demo.changeAnimalName("123"); 14 | demo.changeName("test"); 15 | demo.changeName("test123"); 16 | demo.persist(); 17 | demo.delete(); 18 | } 19 | 20 | @Test 21 | void deleteEntity() { 22 | Demo demo = DomainProxyFactory.create(Demo.class, "test"); 23 | demo.delete(); 24 | } 25 | } -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/dto/request/PageRequestTest.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.dto.request; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.*; 6 | 7 | class PageRequestTest { 8 | 9 | @Test 10 | void test(){ 11 | PageRequest pageRequest = new PageRequest(); 12 | pageRequest.setCurrent(1); 13 | pageRequest.setPageSize(10); 14 | 15 | assertEquals(pageRequest.getCurrent(),1); 16 | assertEquals(pageRequest.getPageSize(),10); 17 | } 18 | 19 | 20 | 21 | } -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/event/DemoChangeEvent.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.event; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | @Setter 8 | @Getter 9 | @AllArgsConstructor 10 | public class DemoChangeEvent implements IEvent { 11 | 12 | private String beforeName; 13 | private String currentName; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/exception/LocaleMessageExceptionTest.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.exception; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | import static org.junit.jupiter.api.Assertions.*; 7 | 8 | @SpringBootTest 9 | class LocaleMessageExceptionTest { 10 | 11 | @Test 12 | void test(){ 13 | LocaleMessageException exception = new LocaleMessageException("api.error"); 14 | assertEquals(exception.getErrMessage(),"this is an error info"); 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/handler/DemoChangeLogHandler.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.handler; 2 | 3 | import com.codingapi.springboot.framework.event.DemoChangeEvent; 4 | import com.codingapi.springboot.framework.event.Handler; 5 | import com.codingapi.springboot.framework.event.IHandler; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | @Slf4j 9 | @Handler 10 | public class DemoChangeLogHandler implements IHandler { 11 | 12 | @Override 13 | public void handler(DemoChangeEvent event) { 14 | log.info("print before name :{},current name :{}", event.getBeforeName(), event.getCurrentName()); 15 | } 16 | 17 | @Override 18 | public void error(Exception exception) { 19 | log.error("DemoChangeLogHandler error", exception); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/handler/DemoCreateHandler.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.handler; 2 | 3 | import com.codingapi.springboot.framework.domain.event.DomainCreateEvent; 4 | import com.codingapi.springboot.framework.event.Handler; 5 | import com.codingapi.springboot.framework.event.IHandler; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | @Slf4j 9 | @Handler 10 | public class DemoCreateHandler implements IHandler { 11 | 12 | @Override 13 | public void handler(DomainCreateEvent event) { 14 | log.info("create domain -> {}", event.getEntity()); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/handler/DemoDeleteHandler.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.handler; 2 | 3 | import com.codingapi.springboot.framework.domain.event.DomainDeleteEvent; 4 | import com.codingapi.springboot.framework.event.Handler; 5 | import com.codingapi.springboot.framework.event.IHandler; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | @Slf4j 9 | @Handler 10 | public class DemoDeleteHandler implements IHandler { 11 | 12 | @Override 13 | public void handler(DomainDeleteEvent event) { 14 | log.info("delete domain -> {}", event.getEntity()); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/handler/DemoPersistEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.handler; 2 | 3 | import com.codingapi.springboot.framework.domain.event.DomainPersistEvent; 4 | import com.codingapi.springboot.framework.event.Handler; 5 | import com.codingapi.springboot.framework.event.IHandler; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | @Slf4j 9 | @Handler 10 | public class DemoPersistEventHandler implements IHandler { 11 | 12 | @Override 13 | public void handler(DomainPersistEvent event) { 14 | log.info("DomainPersistEvent handler {}",event); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/handler/EntityFiledChangeHandler.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.handler; 2 | 3 | import com.codingapi.springboot.framework.domain.event.DomainChangeEvent; 4 | import com.codingapi.springboot.framework.event.Handler; 5 | import com.codingapi.springboot.framework.event.IHandler; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | @Slf4j 9 | @Handler 10 | public class EntityFiledChangeHandler implements IHandler { 11 | 12 | @Override 13 | public void handler(DomainChangeEvent event) { 14 | log.info("field change event -> {}",event); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/math/ArithmeticTest.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.math; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.*; 6 | 7 | class ArithmeticTest { 8 | 9 | @Test 10 | void test() { 11 | // 1 + 1 x 3 / 4 = 1.25 12 | assertEquals(Arithmetic.one().add(1).mul(3).div(4).getDoubleValue(),1.5); 13 | 14 | // 0.1+0.2=0.3 15 | assertEquals(Arithmetic.parse(0.1).add(0.2).getDoubleValue(),0.3); 16 | 17 | // (1.5 x 3.1) + (3.4 x 4.5) = 19.95 18 | assertEquals((Arithmetic.parse(1.5).mul(3.1)).add(Arithmetic.parse(3.4).mul(4.5)).getDoubleValue(),19.95); 19 | } 20 | } -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/query/entity/Demo.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.query.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | @Setter 8 | @Getter 9 | @Table(name = "t_demo") 10 | @Entity 11 | public class Demo { 12 | 13 | @Id 14 | @GeneratedValue(strategy = GenerationType.IDENTITY) 15 | private Integer id; 16 | 17 | private String name; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/query/repository/DemoRepository.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.query.repository; 2 | 3 | import com.codingapi.springboot.framework.query.entity.Demo; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface DemoRepository extends JpaRepository { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/rest/SessionClientTest.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.rest; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertNotNull; 7 | 8 | @Slf4j 9 | public class SessionClientTest { 10 | 11 | @Test 12 | void test(){ 13 | SessionClient client = new SessionClient(); 14 | String html = client.getHtml("https://www.baidu.com"); 15 | assertNotNull(html); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/utils/FullDateFormatUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.utils; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | 6 | import static org.junit.jupiter.api.Assertions.*; 7 | 8 | class FullDateFormatUtilsTest { 9 | 10 | @Test 11 | void convert() { 12 | long time = 1663590528793L; 13 | String data =FullDateFormatUtils.convert(time); 14 | assertEquals(data,"2022-09-19 20:28:48"); 15 | } 16 | } -------------------------------------------------------------------------------- /springboot-starter/src/test/java/com/codingapi/springboot/framework/utils/TrustAnyHttpClientFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.codingapi.springboot.framework.utils; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.http.client.ClientHttpRequestFactory; 5 | import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; 6 | import org.springframework.web.client.RestTemplate; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertNotNull; 9 | 10 | class TrustAnyHttpClientFactoryTest { 11 | 12 | @Test 13 | void createTrustAnyHttpClient() { 14 | ClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(TrustAnyHttpClientFactory.createTrustAnyHttpClient()); 15 | RestTemplate restTemplate = new RestTemplate(factory); 16 | String response = restTemplate.getForObject("https://www.baidu.com",String.class); 17 | assertNotNull(response); 18 | } 19 | } -------------------------------------------------------------------------------- /springboot-starter/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8088 2 | spring.datasource.driver-class-name=org.h2.Driver 3 | spring.datasource.url=jdbc:h2:file:./test.db 4 | spring.jpa.database-platform=org.hibernate.dialect.H2Dialect 5 | spring.jpa.hibernate.ddl-auto=create-drop 6 | spring.jpa.show-sql=true -------------------------------------------------------------------------------- /springboot-starter/src/test/resources/messages.properties: -------------------------------------------------------------------------------- 1 | api.error=this is an error info --------------------------------------------------------------------------------