From d5ffb57327f0a7145c0e22dc87ef663017c82773 Mon Sep 17 00:00:00 2001 From: suger <304902140@qq.com> Date: Fri, 18 Jan 2019 14:15:22 +0800 Subject: [PATCH] first --- .gitignore | 10 + code-generator/pom.xml | 78 ++ .../src/main/java/com/qmrz/CodeGenerator.java | 20 + .../com/qmrz/generator/ApiSyncGenerator.java | 43 ++ .../qmrz/generator/ControllerGenerator.java | 45 ++ .../com/qmrz/generator/DBReadmeGenerator.java | 47 ++ .../com/qmrz/generator/GeneratorUtil.java | 29 + .../generator/InterfaceReadmeGenerator.java | 44 ++ .../com/qmrz/generator/MapperGenerator.java | 44 ++ .../com/qmrz/generator/ServiceGenerator.java | 42 ++ .../qmrz/generator/ServiceImplGenerator.java | 42 ++ .../qmrz/service/Impl/TableServiceImpl.java | 47 ++ .../java/com/qmrz/service/TableService.java | 9 + .../main/java/com/qmrz/utils/CGHelper.java | 70 ++ .../src/main/resources/application.yml | 25 + .../src/main/resources/mapper/TableMapper.xml | 36 + .../src/main/resources/template/api_sync.ftl | 114 +++ .../main/resources/template/controller.ftl | 66 ++ .../src/main/resources/template/db_readme.md | 19 + .../resources/template/db_tables_readme.md | 10 + .../template/inteface_tables_readme.md | 44 ++ .../src/main/resources/template/mapper.ftl | 117 +++ .../main/resources/template/mapper.ftl.backup | 140 ++++ .../src/main/resources/template/service.ftl | 12 + .../main/resources/template/serviceImpl.ftl | 22 + .../src/test/TestCodeGenerator.java | 89 +++ common/pom.xml | 26 + .../java/com/qmrz/BaseAdminController.java | 11 + .../main/java/com/qmrz/admin/AdminLogin.java | 99 +++ .../java/com/qmrz/admin/AdminLoginInfo.java | 12 + .../java/com/qmrz/admin/CustomerInfo.java | 14 + .../src/main/java/com/qmrz/config/Config.java | 75 ++ .../java/com/qmrz/config/ConfigDBInfo.java | 24 + .../java/com/qmrz/config/ConfigDBUtils.java | 149 ++++ .../com/qmrz/config/ConfigUploadFileInfo.java | 18 + .../java/com/qmrz/config/SecurityConfig.java | 15 + .../main/java/com/qmrz/config/SysInfo.java | 79 ++ .../java/com/qmrz/constants/ABMessage.java | 6 + .../com/qmrz/constants/ConstantValue.java | 7 + .../main/java/com/qmrz/dto/PageMapDTO.java | 33 + .../main/java/com/qmrz/dto/ParamCodeDTO.java | 19 + .../main/java/com/qmrz/dto/ParamCustomer.java | 19 + .../main/java/com/qmrz/dto/ParamIDDTO.java | 45 ++ .../java/com/qmrz/dto/ParamIDPageDTO.java | 29 + .../java/com/qmrz/dto/ParamLongIDDTO.java | 20 + .../main/java/com/qmrz/dto/ParamMoneyDTO.java | 24 + .../main/java/com/qmrz/dto/ParamNameDTO.java | 40 + .../main/java/com/qmrz/dto/ParamPageDTO.java | 61 ++ .../main/java/com/qmrz/dto/ParamTypeDTO.java | 19 + .../java/com/qmrz/dto/SecurityAdminDTO.java | 35 + .../main/java/com/qmrz/dto/TParamIDDTO.java | 25 + .../java/com/qmrz/exception/ABException.java | 53 ++ .../com/qmrz/exception/FailureException.java | 14 + .../exception/GlobalControllerException.java | 66 ++ .../qmrz/exception/GlobalSpringException.java | 36 + .../exception/NotPermissionException.java | 16 + .../exception/PoliceNotLoginException.java | 12 + .../qmrz/exception/UserNotLoginException.java | 12 + .../WXUserNotAuthorizationException.java | 12 + .../main/java/com/qmrz/mybatis/BasePO.java | 274 +++++++ .../qmrz/mybatis/BaseProviderSqlSource.java | 205 +++++ .../main/java/com/qmrz/mybatis/DBWrapper.java | 5 + .../src/main/java/com/qmrz/mybatis/INull.java | 4 + .../main/java/com/qmrz/mybatis/Mapper.java | 131 ++++ .../java/com/qmrz/mybatis/MapperScan.java | 234 ++++++ .../qmrz/mybatis/MapperScannerConfigurer.java | 33 + .../java/com/qmrz/mybatis/MapperUtil.java | 96 +++ common/src/main/java/com/qmrz/mybatis/PO.java | 25 + .../java/com/qmrz/mybatis/POPropertie.java | 28 + .../com/qmrz/mybatis/POPropertieValue.java | 18 + .../main/java/com/qmrz/mybatis/POProxy.java | 61 ++ .../main/java/com/qmrz/mybatis/POUtil.java | 463 ++++++++++++ .../main/java/com/qmrz/mybatis/SqlUtil.java | 344 +++++++++ .../com/qmrz/mybatis/annotation/DBType.java | 13 + .../qmrz/mybatis/annotation/FieldName.java | 9 + .../java/com/qmrz/mybatis/annotation/ID.java | 12 + .../mybatis/annotation/OrderByDefault.java | 13 + .../qmrz/mybatis/annotation/TableName.java | 13 + .../qmrz/mybatis/service/AbstractService.java | 91 +++ .../com/qmrz/mybatis/service/BaseService.java | 90 +++ .../com/qmrz/mybatis/sql/AbsWrapperData.java | 131 ++++ .../com/qmrz/mybatis/sql/BaseWrapper.java | 292 +++++++ .../com/qmrz/mybatis/sql/ConditionCount.java | 18 + .../mybatis/sql/ConditionGeneralValue.java | 17 + .../java/com/qmrz/mybatis/sql/IWrapper.java | 4 + .../java/com/qmrz/mybatis/sql/Wrapper.java | 7 + .../com/qmrz/mybatis/sql/WrapperResolve.java | 44 ++ .../com/qmrz/mybatis/sql/WrapperUtil.java | 23 + .../mybatis/sql/sqlnode/SqlNodeWrapper.java | 304 ++++++++ .../qmrz/mybatis/sql/sqlnode/UpdateParam.java | 13 + .../qmrz/mybatis/sql/statement/AndBlock.java | 18 + .../sql/statement/ConditionBetween.java | 55 ++ .../sql/statement/ConditionGeneral.java | 57 ++ .../mybatis/sql/statement/ConditionIn.java | 56 ++ .../mybatis/sql/statement/ConditionLike.java | 55 ++ .../mybatis/sql/statement/DeleteFrom.java | 36 + .../qmrz/mybatis/sql/statement/FromTable.java | 36 + .../com/qmrz/mybatis/sql/statement/Limit.java | 57 ++ .../qmrz/mybatis/sql/statement/OrBlock.java | 18 + .../mybatis/sql/statement/OrderByDefault.java | 35 + .../mybatis/sql/statement/SelectAllField.java | 36 + .../qmrz/mybatis/sql/statement/StrWhere.java | 29 + .../qmrz/mybatis/sql/statement/UpdateSet.java | 37 + .../mybatis/sql/statement/WhereBlock.java | 18 + .../main/java/com/qmrz/utils/CacheUtil.java | 27 + .../main/java/com/qmrz/utils/ConvertUtil.java | 334 ++++++++ .../main/java/com/qmrz/utils/DBHelper.java | 184 +++++ .../java/com/qmrz/utils/DateTimeUtil.java | 145 ++++ .../java/com/qmrz/utils/ExportPOIUtils.java | 191 +++++ common/src/main/java/com/qmrz/utils/Fn.java | 375 +++++++++ .../utils/FreemarkerExceptionHandler.java | 14 + .../main/java/com/qmrz/utils/Identities.java | 80 ++ .../main/java/com/qmrz/utils/ImageUtil.java | 39 + .../src/main/java/com/qmrz/utils/JWTUtil.java | 38 + common/src/main/java/com/qmrz/utils/Json.java | 23 + .../java/com/qmrz/utils/ListPageUtil.java | 45 ++ .../src/main/java/com/qmrz/utils/MD5Util.java | 55 ++ .../main/java/com/qmrz/utils/MapChain.java | 37 + .../src/main/java/com/qmrz/utils/MapUtil.java | 50 ++ .../MetaspaceEmptyCapacityExpansion.java | 11 + .../main/java/com/qmrz/utils/MoneyUtil.java | 38 + .../main/java/com/qmrz/utils/PackageUtil.java | 142 ++++ .../main/java/com/qmrz/utils/PageData.java | 49 ++ .../main/java/com/qmrz/utils/ParamUtil.java | 5 + common/src/main/java/com/qmrz/utils/RD.java | 119 +++ .../src/main/java/com/qmrz/utils/RDCode.java | 45 ++ .../java/com/qmrz/utils/ReStreamInput.java | 26 + .../src/main/java/com/qmrz/utils/Session.java | 22 + .../com/qmrz/utils/SpringContextUtil.java | 37 + .../main/java/com/qmrz/utils/StreamUtil.java | 35 + .../java/com/qmrz/utils/ValidateUtil.java | 6 + .../java/com/qmrz/utils/VerifyCodeUtil.java | 299 ++++++++ common/src/main/java/com/qmrz/utils/Web.java | 215 ++++++ .../src/main/java/com/qmrz/utils/XMLUtil.java | 113 +++ .../utils/classload/JavaStringCompiler.java | 71 ++ .../utils/classload/MemoryClassLoader.java | 32 + .../classload/MemoryJavaFileManager.java | 84 +++ .../java/com/qmrz/utils/coordinate/Angle.java | 89 +++ .../java/com/qmrz/utils/coordinate/Gps.java | 20 + .../qmrz/utils/coordinate/PositionUtil.java | 98 +++ .../com/qmrz/utils/enumutil/EnumUtil.java | 60 ++ .../java/com/qmrz/utils/enumutil/IEmun.java | 16 + .../java/com/qmrz/utils/http/HttpMethod.java | 6 + .../java/com/qmrz/utils/http/HttpResult.java | 20 + .../java/com/qmrz/utils/http/HttpUtil.java | 378 ++++++++++ .../com/qmrz/utils/http/MyTrustManager.java | 23 + .../java/com/qmrz/utils/proxy/HttpProxy.java | 101 +++ .../com/qmrz/utils/proxy/ProxyServlet.java | 713 ++++++++++++++++++ .../utils/proxy/URITemplateProxyServlet.java | 146 ++++ .../com/qmrz/utils/shiro/IShiroRealm.java | 5 + .../java/com/qmrz/utils/shiro/ShiroUtil.java | 33 + .../java/com/qmrz/utils/tree/TreeBuilder.java | 296 ++++++++ .../java/com/qmrz/utils/tree/TreeNode.java | 20 + .../java/com/qmrz/utils/validate/Phone.java | 17 + .../com/qmrz/utils/validate/PhoneMulti.java | 17 + .../utils/validate/PhoneMultiValidate.java | 18 + .../qmrz/utils/validate/PhoneValidate.java | 18 + pom.xml | 372 +++++++++ readme.md | 108 +++ 159 files changed, 11507 insertions(+) create mode 100644 .gitignore create mode 100644 code-generator/pom.xml create mode 100644 code-generator/src/main/java/com/qmrz/CodeGenerator.java create mode 100644 code-generator/src/main/java/com/qmrz/generator/ApiSyncGenerator.java create mode 100644 code-generator/src/main/java/com/qmrz/generator/ControllerGenerator.java create mode 100644 code-generator/src/main/java/com/qmrz/generator/DBReadmeGenerator.java create mode 100644 code-generator/src/main/java/com/qmrz/generator/GeneratorUtil.java create mode 100644 code-generator/src/main/java/com/qmrz/generator/InterfaceReadmeGenerator.java create mode 100644 code-generator/src/main/java/com/qmrz/generator/MapperGenerator.java create mode 100644 code-generator/src/main/java/com/qmrz/generator/ServiceGenerator.java create mode 100644 code-generator/src/main/java/com/qmrz/generator/ServiceImplGenerator.java create mode 100644 code-generator/src/main/java/com/qmrz/service/Impl/TableServiceImpl.java create mode 100644 code-generator/src/main/java/com/qmrz/service/TableService.java create mode 100644 code-generator/src/main/java/com/qmrz/utils/CGHelper.java create mode 100644 code-generator/src/main/resources/application.yml create mode 100644 code-generator/src/main/resources/mapper/TableMapper.xml create mode 100644 code-generator/src/main/resources/template/api_sync.ftl create mode 100644 code-generator/src/main/resources/template/controller.ftl create mode 100644 code-generator/src/main/resources/template/db_readme.md create mode 100644 code-generator/src/main/resources/template/db_tables_readme.md create mode 100644 code-generator/src/main/resources/template/inteface_tables_readme.md create mode 100644 code-generator/src/main/resources/template/mapper.ftl create mode 100644 code-generator/src/main/resources/template/mapper.ftl.backup create mode 100644 code-generator/src/main/resources/template/service.ftl create mode 100644 code-generator/src/main/resources/template/serviceImpl.ftl create mode 100644 code-generator/src/test/TestCodeGenerator.java create mode 100644 common/pom.xml create mode 100644 common/src/main/java/com/qmrz/BaseAdminController.java create mode 100644 common/src/main/java/com/qmrz/admin/AdminLogin.java create mode 100644 common/src/main/java/com/qmrz/admin/AdminLoginInfo.java create mode 100644 common/src/main/java/com/qmrz/admin/CustomerInfo.java create mode 100644 common/src/main/java/com/qmrz/config/Config.java create mode 100644 common/src/main/java/com/qmrz/config/ConfigDBInfo.java create mode 100644 common/src/main/java/com/qmrz/config/ConfigDBUtils.java create mode 100644 common/src/main/java/com/qmrz/config/ConfigUploadFileInfo.java create mode 100644 common/src/main/java/com/qmrz/config/SecurityConfig.java create mode 100644 common/src/main/java/com/qmrz/config/SysInfo.java create mode 100644 common/src/main/java/com/qmrz/constants/ABMessage.java create mode 100644 common/src/main/java/com/qmrz/constants/ConstantValue.java create mode 100644 common/src/main/java/com/qmrz/dto/PageMapDTO.java create mode 100644 common/src/main/java/com/qmrz/dto/ParamCodeDTO.java create mode 100644 common/src/main/java/com/qmrz/dto/ParamCustomer.java create mode 100644 common/src/main/java/com/qmrz/dto/ParamIDDTO.java create mode 100644 common/src/main/java/com/qmrz/dto/ParamIDPageDTO.java create mode 100644 common/src/main/java/com/qmrz/dto/ParamLongIDDTO.java create mode 100644 common/src/main/java/com/qmrz/dto/ParamMoneyDTO.java create mode 100644 common/src/main/java/com/qmrz/dto/ParamNameDTO.java create mode 100644 common/src/main/java/com/qmrz/dto/ParamPageDTO.java create mode 100644 common/src/main/java/com/qmrz/dto/ParamTypeDTO.java create mode 100644 common/src/main/java/com/qmrz/dto/SecurityAdminDTO.java create mode 100644 common/src/main/java/com/qmrz/dto/TParamIDDTO.java create mode 100644 common/src/main/java/com/qmrz/exception/ABException.java create mode 100644 common/src/main/java/com/qmrz/exception/FailureException.java create mode 100644 common/src/main/java/com/qmrz/exception/GlobalControllerException.java create mode 100644 common/src/main/java/com/qmrz/exception/GlobalSpringException.java create mode 100644 common/src/main/java/com/qmrz/exception/NotPermissionException.java create mode 100644 common/src/main/java/com/qmrz/exception/PoliceNotLoginException.java create mode 100644 common/src/main/java/com/qmrz/exception/UserNotLoginException.java create mode 100644 common/src/main/java/com/qmrz/exception/WXUserNotAuthorizationException.java create mode 100644 common/src/main/java/com/qmrz/mybatis/BasePO.java create mode 100644 common/src/main/java/com/qmrz/mybatis/BaseProviderSqlSource.java create mode 100644 common/src/main/java/com/qmrz/mybatis/DBWrapper.java create mode 100644 common/src/main/java/com/qmrz/mybatis/INull.java create mode 100644 common/src/main/java/com/qmrz/mybatis/Mapper.java create mode 100644 common/src/main/java/com/qmrz/mybatis/MapperScan.java create mode 100644 common/src/main/java/com/qmrz/mybatis/MapperScannerConfigurer.java create mode 100644 common/src/main/java/com/qmrz/mybatis/MapperUtil.java create mode 100644 common/src/main/java/com/qmrz/mybatis/PO.java create mode 100644 common/src/main/java/com/qmrz/mybatis/POPropertie.java create mode 100644 common/src/main/java/com/qmrz/mybatis/POPropertieValue.java create mode 100644 common/src/main/java/com/qmrz/mybatis/POProxy.java create mode 100644 common/src/main/java/com/qmrz/mybatis/POUtil.java create mode 100644 common/src/main/java/com/qmrz/mybatis/SqlUtil.java create mode 100644 common/src/main/java/com/qmrz/mybatis/annotation/DBType.java create mode 100644 common/src/main/java/com/qmrz/mybatis/annotation/FieldName.java create mode 100644 common/src/main/java/com/qmrz/mybatis/annotation/ID.java create mode 100644 common/src/main/java/com/qmrz/mybatis/annotation/OrderByDefault.java create mode 100644 common/src/main/java/com/qmrz/mybatis/annotation/TableName.java create mode 100644 common/src/main/java/com/qmrz/mybatis/service/AbstractService.java create mode 100644 common/src/main/java/com/qmrz/mybatis/service/BaseService.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/AbsWrapperData.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/BaseWrapper.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/ConditionCount.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/ConditionGeneralValue.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/IWrapper.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/Wrapper.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/WrapperResolve.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/WrapperUtil.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/sqlnode/SqlNodeWrapper.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/sqlnode/UpdateParam.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/statement/AndBlock.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/statement/ConditionBetween.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/statement/ConditionGeneral.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/statement/ConditionIn.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/statement/ConditionLike.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/statement/DeleteFrom.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/statement/FromTable.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/statement/Limit.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/statement/OrBlock.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/statement/OrderByDefault.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/statement/SelectAllField.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/statement/StrWhere.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/statement/UpdateSet.java create mode 100644 common/src/main/java/com/qmrz/mybatis/sql/statement/WhereBlock.java create mode 100644 common/src/main/java/com/qmrz/utils/CacheUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/ConvertUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/DBHelper.java create mode 100644 common/src/main/java/com/qmrz/utils/DateTimeUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/ExportPOIUtils.java create mode 100644 common/src/main/java/com/qmrz/utils/Fn.java create mode 100644 common/src/main/java/com/qmrz/utils/FreemarkerExceptionHandler.java create mode 100644 common/src/main/java/com/qmrz/utils/Identities.java create mode 100644 common/src/main/java/com/qmrz/utils/ImageUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/JWTUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/Json.java create mode 100644 common/src/main/java/com/qmrz/utils/ListPageUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/MD5Util.java create mode 100644 common/src/main/java/com/qmrz/utils/MapChain.java create mode 100644 common/src/main/java/com/qmrz/utils/MapUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/MetaspaceEmptyCapacityExpansion.java create mode 100644 common/src/main/java/com/qmrz/utils/MoneyUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/PackageUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/PageData.java create mode 100644 common/src/main/java/com/qmrz/utils/ParamUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/RD.java create mode 100644 common/src/main/java/com/qmrz/utils/RDCode.java create mode 100644 common/src/main/java/com/qmrz/utils/ReStreamInput.java create mode 100644 common/src/main/java/com/qmrz/utils/Session.java create mode 100644 common/src/main/java/com/qmrz/utils/SpringContextUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/StreamUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/ValidateUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/VerifyCodeUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/Web.java create mode 100644 common/src/main/java/com/qmrz/utils/XMLUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/classload/JavaStringCompiler.java create mode 100644 common/src/main/java/com/qmrz/utils/classload/MemoryClassLoader.java create mode 100644 common/src/main/java/com/qmrz/utils/classload/MemoryJavaFileManager.java create mode 100644 common/src/main/java/com/qmrz/utils/coordinate/Angle.java create mode 100644 common/src/main/java/com/qmrz/utils/coordinate/Gps.java create mode 100644 common/src/main/java/com/qmrz/utils/coordinate/PositionUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/enumutil/EnumUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/enumutil/IEmun.java create mode 100644 common/src/main/java/com/qmrz/utils/http/HttpMethod.java create mode 100644 common/src/main/java/com/qmrz/utils/http/HttpResult.java create mode 100644 common/src/main/java/com/qmrz/utils/http/HttpUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/http/MyTrustManager.java create mode 100644 common/src/main/java/com/qmrz/utils/proxy/HttpProxy.java create mode 100644 common/src/main/java/com/qmrz/utils/proxy/ProxyServlet.java create mode 100644 common/src/main/java/com/qmrz/utils/proxy/URITemplateProxyServlet.java create mode 100644 common/src/main/java/com/qmrz/utils/shiro/IShiroRealm.java create mode 100644 common/src/main/java/com/qmrz/utils/shiro/ShiroUtil.java create mode 100644 common/src/main/java/com/qmrz/utils/tree/TreeBuilder.java create mode 100644 common/src/main/java/com/qmrz/utils/tree/TreeNode.java create mode 100644 common/src/main/java/com/qmrz/utils/validate/Phone.java create mode 100644 common/src/main/java/com/qmrz/utils/validate/PhoneMulti.java create mode 100644 common/src/main/java/com/qmrz/utils/validate/PhoneMultiValidate.java create mode 100644 common/src/main/java/com/qmrz/utils/validate/PhoneValidate.java create mode 100644 pom.xml create mode 100644 readme.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8cb5f1f --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +**/target/ +**/resources/code/ +/.idea/ +*.iml +/logs +.classpath +.project +.factorypath +**/.settings/ +.vscode/ \ No newline at end of file diff --git a/code-generator/pom.xml b/code-generator/pom.xml new file mode 100644 index 0000000..fae5245 --- /dev/null +++ b/code-generator/pom.xml @@ -0,0 +1,78 @@ + + + + codeGenerate + com.qmrz + 1.0 + + 4.0.0 + code-generator + jar + + + + + org.mybatis.generator + mybatis-generator-maven-plugin + 1.3.7 + + + + + org.mybatis.generator + mybatis-generator-core + 1.3.7 + + + + com.qmrz + common + 1.0 + + + + mysql + mysql-connector-java + 8.0.11 + + + + + org.freemarker + freemarker + 2.3.28 + + + org.testng + testng + RELEASE + test + + + + + + CodeGenerator + + + org.springframework.boot + spring-boot-maven-plugin + + + true + com.qmrz.CodeGenerator + -Dfile.encoding=UTF-8 + + + + + exec + + + + + + + \ No newline at end of file diff --git a/code-generator/src/main/java/com/qmrz/CodeGenerator.java b/code-generator/src/main/java/com/qmrz/CodeGenerator.java new file mode 100644 index 0000000..66185bf --- /dev/null +++ b/code-generator/src/main/java/com/qmrz/CodeGenerator.java @@ -0,0 +1,20 @@ +package com.qmrz; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@Slf4j +@SpringBootApplication(exclude={RedisAutoConfiguration.class, + RedisRepositoriesAutoConfiguration.class}) +@EnableTransactionManagement +@EnableCaching +public class CodeGenerator { + public static void main(String[] args) { + SpringApplication.run(CodeGenerator.class, args); + } +} diff --git a/code-generator/src/main/java/com/qmrz/generator/ApiSyncGenerator.java b/code-generator/src/main/java/com/qmrz/generator/ApiSyncGenerator.java new file mode 100644 index 0000000..7b03ab4 --- /dev/null +++ b/code-generator/src/main/java/com/qmrz/generator/ApiSyncGenerator.java @@ -0,0 +1,43 @@ +package com.qmrz.generator; + +import com.qmrz.service.TableService; +import com.qmrz.utils.CGHelper; +import com.qmrz.utils.Fn; +import com.qmrz.utils.MapUtil; +import com.qmrz.utils.SpringContextUtil; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * api同步代码 生成 + */ +public class ApiSyncGenerator { + private TableService tableService; + private String dbName; + + public ApiSyncGenerator(String dbName) { + tableService = SpringContextUtil.getBean(TableService.class); + this.dbName = dbName; + } + + public void generator() { + + List tableList = tableService.getTableList(dbName); + List columnList = tableService.getColumnList(dbName); + GeneratorUtil.setColumnShowName(columnList); + Map result = columnList.stream().collect(Collectors.groupingBy(map -> map.get("table_name"), Collectors.toList())); + + CGHelper cgHelper = new CGHelper("api_sync.ftl", dbName); + + tableList.forEach(item -> { + String table_name = item.get("table_name").toString(); + String table_name2 = Fn.firstUpperCase(table_name); + item.put("columnList", result.get(table_name)); + item.put("dbname", dbName); + item.put("table_name2",table_name2);//首字母大写 + cgHelper.generator("api_sync", table_name2 + "Sync.java", item); + }); + } +} diff --git a/code-generator/src/main/java/com/qmrz/generator/ControllerGenerator.java b/code-generator/src/main/java/com/qmrz/generator/ControllerGenerator.java new file mode 100644 index 0000000..54fa0d4 --- /dev/null +++ b/code-generator/src/main/java/com/qmrz/generator/ControllerGenerator.java @@ -0,0 +1,45 @@ +package com.qmrz.generator; + +import com.qmrz.service.TableService; +import com.qmrz.utils.CGHelper; +import com.qmrz.utils.Fn; +import com.qmrz.utils.SpringContextUtil; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Controller生成 + */ +public class ControllerGenerator { + private TableService tableService; + private String dbName; + + public ControllerGenerator(String dbName) { + tableService = SpringContextUtil.getBean(TableService.class); + this.dbName = dbName; + } + + public void generator() { + + List tableList = tableService.getTableList(dbName); + List columnList = tableService.getColumnList(dbName); + GeneratorUtil.setColumnShowName(columnList); + + Map result = columnList.stream().collect(Collectors.groupingBy(map -> map.get("table_name"), Collectors.toList())); + + CGHelper cgHelper = new CGHelper("controller.ftl", dbName); + + tableList.forEach(item -> { + String table_name = item.get("table_name").toString(); + String table_name2 = Fn.firstUpperCase(table_name); + item.put("columnList", result.get(table_name)); + item.put("dbname", dbName); + item.put("table_name2", table_name2);//首字母大写 + + + cgHelper.generator("controller", table_name2 + "Controller.java", item); + }); + } +} diff --git a/code-generator/src/main/java/com/qmrz/generator/DBReadmeGenerator.java b/code-generator/src/main/java/com/qmrz/generator/DBReadmeGenerator.java new file mode 100644 index 0000000..19dfb93 --- /dev/null +++ b/code-generator/src/main/java/com/qmrz/generator/DBReadmeGenerator.java @@ -0,0 +1,47 @@ +package com.qmrz.generator; + +import com.qmrz.service.TableService; +import com.qmrz.utils.CGHelper; +import com.qmrz.utils.MapUtil; +import com.qmrz.utils.SpringContextUtil; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 数据库字典生成 + */ +public class DBReadmeGenerator { + private TableService tableService; + private String dbName; + + public DBReadmeGenerator(String dbName) { + tableService = SpringContextUtil.getBean(TableService.class); + this.dbName = dbName; + } + + public void generator() { + + List tableList = tableService.getTableList(dbName); + List columnList = tableService.getColumnList(dbName); + + Map result = columnList.stream().collect(Collectors.groupingBy(map -> map.get("table_name"), Collectors.toList())); + + CGHelper cgHelperTable = new CGHelper("db_tables_readme.md", dbName); + cgHelperTable.generator("", "db_tables.md", MapUtil.newMap() + .put("dbname", dbName) + .put("tableList", tableList) + .getMap() + ); + + CGHelper cgHelper = new CGHelper("db_readme.md", dbName); + + tableList.forEach(item -> { + String table_name = item.get("table_name").toString(); + item.put("columnList", result.get(table_name)); + item.put("dbname", dbName); + cgHelper.generator("readme", "db_" + table_name + ".md", item); + }); + } +} diff --git a/code-generator/src/main/java/com/qmrz/generator/GeneratorUtil.java b/code-generator/src/main/java/com/qmrz/generator/GeneratorUtil.java new file mode 100644 index 0000000..62959fc --- /dev/null +++ b/code-generator/src/main/java/com/qmrz/generator/GeneratorUtil.java @@ -0,0 +1,29 @@ +package com.qmrz.generator; + +import java.util.List; +import java.util.Map; + +/** + * 生成基础工具 + * @Author: suger + */ +public class GeneratorUtil { + /** + * 增加显示名 + * @param columnList + */ + public static void setColumnShowName(List columnList){ + for (Map item : columnList) { + String column_name_show_name = String.valueOf(item.get("column_comment")); + int space_indexof = column_name_show_name.indexOf(" "); + if (space_indexof > 0) { + column_name_show_name = column_name_show_name.substring(0, space_indexof).trim(); + } + if (column_name_show_name.trim().length() == 0) { + column_name_show_name = String.valueOf(item.get("column_name")).trim(); + } + + item.put("column_name_show_name", column_name_show_name);//获取注释的第一个单词,到英文空格为止 + } + } +} diff --git a/code-generator/src/main/java/com/qmrz/generator/InterfaceReadmeGenerator.java b/code-generator/src/main/java/com/qmrz/generator/InterfaceReadmeGenerator.java new file mode 100644 index 0000000..ed9d034 --- /dev/null +++ b/code-generator/src/main/java/com/qmrz/generator/InterfaceReadmeGenerator.java @@ -0,0 +1,44 @@ +package com.qmrz.generator; + +import com.qmrz.service.TableService; +import com.qmrz.utils.CGHelper; +import com.qmrz.utils.MapUtil; +import com.qmrz.utils.SpringContextUtil; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class InterfaceReadmeGenerator { + private TableService tableService; + private String dbName; + + public InterfaceReadmeGenerator(String dbName) { + tableService = SpringContextUtil.getBean(TableService.class); + this.dbName = dbName; + } + + public void generator() { + + List tableList = tableService.getTableList(dbName); + List columnList = tableService.getColumnList(dbName); + + Map result = columnList.stream().collect(Collectors.groupingBy(map -> map.get("table_name"), Collectors.toList())); + + CGHelper cgHelperTable = new CGHelper("inteface_tables_readme.md", dbName); + cgHelperTable.generator("", "inteface_tables_readme.md", MapUtil.newMap() + .put("dbname", dbName) + .put("tableList", tableList) + .getMap() + ); + CGHelper cgHelper = new CGHelper("inteface_tables_readme.md", dbName); + + tableList.forEach(item -> { + String table_name = item.get("table_name").toString(); + item.put("columnList", result.get(table_name)); + item.put("dbname", dbName); + item.put("filename", "inteface_" + table_name + "_readme.md"); + cgHelper.generator("readme", "inteface_" + table_name + "_readme.md", item); + }); + } +} diff --git a/code-generator/src/main/java/com/qmrz/generator/MapperGenerator.java b/code-generator/src/main/java/com/qmrz/generator/MapperGenerator.java new file mode 100644 index 0000000..804a46e --- /dev/null +++ b/code-generator/src/main/java/com/qmrz/generator/MapperGenerator.java @@ -0,0 +1,44 @@ +package com.qmrz.generator; + +import com.qmrz.service.TableService; +import com.qmrz.utils.CGHelper; +import com.qmrz.utils.Fn; +import com.qmrz.utils.MapUtil; +import com.qmrz.utils.SpringContextUtil; +import org.apache.commons.lang.StringUtils; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Mapper生成 + */ +public class MapperGenerator { + private TableService tableService; + private String dbName; + + public MapperGenerator(String dbName) { + tableService = SpringContextUtil.getBean(TableService.class); + this.dbName = dbName; + } + + public void generator() { + + List tableList = tableService.getTableList(dbName); + List columnList = tableService.getColumnList(dbName); + + Map result = columnList.stream().collect(Collectors.groupingBy(map -> map.get("table_name"), Collectors.toList())); + + CGHelper cgHelper = new CGHelper("mapper.ftl", dbName); + + tableList.forEach(item -> { + String table_name = item.get("table_name").toString(); + String table_name2 = Fn.firstUpperCase(table_name); + item.put("columnList", result.get(table_name)); + item.put("dbname", dbName); + item.put("table_name2",table_name2);//首字母大写 + cgHelper.generator("mapper", table_name2 + "Mapper.xml", item); + }); + } +} diff --git a/code-generator/src/main/java/com/qmrz/generator/ServiceGenerator.java b/code-generator/src/main/java/com/qmrz/generator/ServiceGenerator.java new file mode 100644 index 0000000..239c5e5 --- /dev/null +++ b/code-generator/src/main/java/com/qmrz/generator/ServiceGenerator.java @@ -0,0 +1,42 @@ +package com.qmrz.generator; + +import com.qmrz.service.TableService; +import com.qmrz.utils.CGHelper; +import com.qmrz.utils.Fn; +import com.qmrz.utils.SpringContextUtil; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Service生成 + */ +public class ServiceGenerator { + private TableService tableService; + private String dbName; + + public ServiceGenerator(String dbName) { + tableService = SpringContextUtil.getBean(TableService.class); + this.dbName = dbName; + } + + public void generator() { + + List tableList = tableService.getTableList(dbName); + List columnList = tableService.getColumnList(dbName); + + Map result = columnList.stream().collect(Collectors.groupingBy(map -> map.get("table_name"), Collectors.toList())); + + CGHelper cgHelper = new CGHelper("service.ftl", dbName); + + tableList.forEach(item -> { + String table_name = item.get("table_name").toString(); + String table_name2 = Fn.firstUpperCase(table_name); + item.put("columnList", result.get(table_name)); + item.put("dbname", dbName); + item.put("table_name2",table_name2);//首字母大写 + cgHelper.generator("service", table_name2 + "Service.java", item); + }); + } +} diff --git a/code-generator/src/main/java/com/qmrz/generator/ServiceImplGenerator.java b/code-generator/src/main/java/com/qmrz/generator/ServiceImplGenerator.java new file mode 100644 index 0000000..f7162e0 --- /dev/null +++ b/code-generator/src/main/java/com/qmrz/generator/ServiceImplGenerator.java @@ -0,0 +1,42 @@ +package com.qmrz.generator; + +import com.qmrz.service.TableService; +import com.qmrz.utils.CGHelper; +import com.qmrz.utils.Fn; +import com.qmrz.utils.SpringContextUtil; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * ServiceImpl生成 + */ +public class ServiceImplGenerator { + private TableService tableService; + private String dbName; + + public ServiceImplGenerator(String dbName) { + tableService = SpringContextUtil.getBean(TableService.class); + this.dbName = dbName; + } + + public void generator() { + + List tableList = tableService.getTableList(dbName); + List columnList = tableService.getColumnList(dbName); + + Map result = columnList.stream().collect(Collectors.groupingBy(map -> map.get("table_name"), Collectors.toList())); + + CGHelper cgHelper = new CGHelper("serviceImpl.ftl", dbName); + + tableList.forEach(item -> { + String table_name = item.get("table_name").toString(); + String table_name2 = Fn.firstUpperCase(table_name); + item.put("columnList", result.get(table_name)); + item.put("dbname", dbName); + item.put("table_name2",table_name2);//首字母大写 + cgHelper.generator("serviceImpl", table_name2 + "ServiceImpl.java", item); + }); + } +} diff --git a/code-generator/src/main/java/com/qmrz/service/Impl/TableServiceImpl.java b/code-generator/src/main/java/com/qmrz/service/Impl/TableServiceImpl.java new file mode 100644 index 0000000..2ca1d6c --- /dev/null +++ b/code-generator/src/main/java/com/qmrz/service/Impl/TableServiceImpl.java @@ -0,0 +1,47 @@ +package com.qmrz.service.Impl; + +import com.qmrz.service.TableService; +import com.qmrz.utils.DBHelper; +import com.qmrz.utils.MapUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +/** + * 表结构查询 + */ +@Service +public class TableServiceImpl implements TableService { + @Autowired + DBHelper dbHelper; + + /** + * 获取指定数据库的所有表结构 + * @param dbName + * @return + */ + @Override + public List getColumnList(String dbName) { + return dbHelper.selectList("TableMapper.getColumnList" + , MapUtil.newMap() + .put("dbname", dbName) + .getMap() + ); + } + + /** + * 获取指定数据库的所有表 + * @param dbName + * @return + */ + @Override + public List getTableList(String dbName) { + return dbHelper.selectList("TableMapper.getTableList" + , MapUtil.newMap() + .put("dbname", dbName) + .getMap() + ); + } +} diff --git a/code-generator/src/main/java/com/qmrz/service/TableService.java b/code-generator/src/main/java/com/qmrz/service/TableService.java new file mode 100644 index 0000000..c5c4496 --- /dev/null +++ b/code-generator/src/main/java/com/qmrz/service/TableService.java @@ -0,0 +1,9 @@ +package com.qmrz.service; + +import java.util.List; +import java.util.Map; + +public interface TableService { + List getColumnList(String dbName); + List getTableList(String dbName); +} diff --git a/code-generator/src/main/java/com/qmrz/utils/CGHelper.java b/code-generator/src/main/java/com/qmrz/utils/CGHelper.java new file mode 100644 index 0000000..11ffdec --- /dev/null +++ b/code-generator/src/main/java/com/qmrz/utils/CGHelper.java @@ -0,0 +1,70 @@ +package com.qmrz.utils; + +import freemarker.template.Configuration; +import freemarker.template.Template; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; + +import java.io.*; +import java.util.HashMap; +import java.util.Map; + +/** + * 生成帮助类(CodeGenerator) + */ +@Slf4j +public class CGHelper { + private final String templatePath = "src/main/resources/template"; + private String savePath; + + private String ftlName; + + public CGHelper(String ftlName, String saveDir) { + this.ftlName = ftlName; + this.savePath = "src/main/resources/code/" + saveDir; + } + + /** + * 写入文件 + * + * @param saveFileName + * @param viewModel + */ + public void generator(String saveDir, String saveFileName, Map viewModel) { + Configuration configuration = new Configuration(); + configuration.setClassicCompatible(true); + Writer out = null; + try { + configuration.setDirectoryForTemplateLoading(new File(templatePath)); + Template template = configuration.getTemplate(ftlName); + + String save; + if (StringUtils.isEmpty(saveDir)) { + save = savePath; + } else { + save = savePath + "\\" + saveDir; + } + + File fileDir = new File(save); + if (!fileDir.exists() && !fileDir.isDirectory()) { + fileDir.mkdirs(); + } + + File docFile = new File(save + "\\" + saveFileName); + out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(docFile))); + + template.process(viewModel, out); + log.info("成功生成:" + saveFileName); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (null != out) { + out.flush(); + } + } catch (Exception e2) { + e2.printStackTrace(); + } + } + } +} diff --git a/code-generator/src/main/resources/application.yml b/code-generator/src/main/resources/application.yml new file mode 100644 index 0000000..9dae747 --- /dev/null +++ b/code-generator/src/main/resources/application.yml @@ -0,0 +1,25 @@ +server: + port: 109086 + +sys: + name: 代码生成 + +spring: + application: + name: code-generator + + +db: + driver: com.mysql.cj.jdbc.Driver +# url: jdbc:mysql://qmrz.cpowvfndzbei.rds.cn-northwest-1.amazonaws.com.cn:3306/qmrz?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC + url: jdbc:mysql://qmrz-ga.cpowvfndzbei.rds.cn-northwest-1.amazonaws.com.cn:3306/qmrzga-dev?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC + username: qmrz + password: Qmrz2018 + +logging: + level: + com.ab.domain.mapper: debug + + + + diff --git a/code-generator/src/main/resources/mapper/TableMapper.xml b/code-generator/src/main/resources/mapper/TableMapper.xml new file mode 100644 index 0000000..cd47b46 --- /dev/null +++ b/code-generator/src/main/resources/mapper/TableMapper.xml @@ -0,0 +1,36 @@ + + + + + + + + + + \ No newline at end of file diff --git a/code-generator/src/main/resources/template/api_sync.ftl b/code-generator/src/main/resources/template/api_sync.ftl new file mode 100644 index 0000000..db3eea6 --- /dev/null +++ b/code-generator/src/main/resources/template/api_sync.ftl @@ -0,0 +1,114 @@ +package com.qmrz.syncapi; + +import com.alibaba.fastjson.JSONArray; +import com.qmrz.exception.ABException; +import com.qmrz.utils.*; +import lombok.extern.slf4j.Slf4j; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 同步 ${table_name},${table_comment} + */ +@Slf4j +public class ${table_name2}Sync extends BaseSync { + private String syncStartDate; + private String syncEndDate; + + public ${table_name2}Sync(String syncStartDate, String syncEndDate) { + this.syncStartDate = syncStartDate; + + //结束日期需要加一天,api同步时不包含结束日期 + this.syncEndDate = DateTimeUtil.datePlus(syncEndDate, 1); + } + + @Override + protected Map getSyncFieldMapping() { + //注意:不包含createtime,若是子表,则外键ID也不包含 + Map fieldMapping = new HashMap<>(); + <#list columnList as item> + <#if item.column_name != "createtime"> + fieldMapping.put("${item.column_name}", "${item.column_name_show_name}"); + + + + return fieldMapping; + } + + public JSONArray getOtherList() { + throw new ABException("方法未实现"); + //return this.getSubList("子记录", (rowParent, rowSub) -> { + // rowSub.put("外键id", rowParent.get("id")); + //}); + } + + @Override + protected String insertMapID() { + return "${table_name2}Mapper.sync_batch_insert"; + } + + @Override + protected String updateMapID() { + return "${table_name2}Mapper.sync_batch_update"; + } + + @Override + protected String deleteMapID() { + return "${table_name2}Mapper.sync_batch_delete"; + } + + @Override + protected String getTableName() { + return "${table_name}"; + } + + @Override + protected String getPrimaryFieldName() { + return "id"; + } + + @Override + protected String getSyncUrl() { + throw new ABException("方法未实现"); + } + + @Override + protected boolean ispage() { + return true; + } + + @Override + protected void insertAddField(Map insertMap) { + insertMap.put("createtime", DateTimeUtil.format(LocalDateTime.now())); + } + + /** + * 查询DB数据,用与api数据比对是否增、删、改 + * @return + */ + @Override + protected List selectDB() { + return SpringContextUtil.getBean(DBHelper.class).selectList("${table_name2}Mapper.sync_batch_select"); + } + + /** + * 若需要api数据时(如主表),返回为false,否则true + * @return + */ + @Override + protected boolean isOrigin() { + return false; + } + + /** + * 若不需要api数据时,请先填充 this.originApi + * @return + */ + @Override + protected JSONArray originApiData() { + return null; + } +} diff --git a/code-generator/src/main/resources/template/controller.ftl b/code-generator/src/main/resources/template/controller.ftl new file mode 100644 index 0000000..b24e711 --- /dev/null +++ b/code-generator/src/main/resources/template/controller.ftl @@ -0,0 +1,66 @@ +package com.qmrz.controller.a1; + +import com.qmrz.controller.base.BaseController; +import com.qmrz.service.${table_name2}Service; +import com.qmrz.utils.ExportPOIUtils; +import com.qmrz.utils.RD; +import com.qmrz.utils.Web; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + * ${table_name},${table_comment} + * Automatic generation + */ +@Slf4j +@RequestMapping("/a1/${table_name}") +@RestController +public class ${table_name2}Controller extends BaseController { + ${table_name2}Service ${table_name}Service; + public ${table_name2}Controller(${table_name2}Service ${table_name}Service){ + super(${table_name}Service); + this.${table_name}Service = ${table_name}Service; + } + + @RequestMapping("insert") + @Override + public RD insert(@RequestBody Map insertData) { + return RD.failure("未开启 insert 操作"); + } + + @RequestMapping("update") + @Override + public RD update(@RequestBody Map data) { + return RD.failure("未开启 update 操作"); + } + + @RequestMapping("delete") + @Override + public RD delete(@RequestBody Map where) { + return RD.failure("未开启 delete 操作"); + } + + /** + * 导出excel + * @param map + */ + @RequestMapping("export") + public void export(@RequestBody Map map) { + //db字段名 + String dbColumn[] = {<#list columnList as item>"${item.column_name}"<#if item_has_next>,}; + //excel列名 + String excelColumn[] = {<#list columnList as item>"${item.column_name_show_name}"<#if item_has_next>,}; + List resultList = this.${table_name}Service.selectList(map); + try { + ExportPOIUtils.start_download(Web.getResponse(), "${table_name}", resultList, excelColumn, dbColumn); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/code-generator/src/main/resources/template/db_readme.md b/code-generator/src/main/resources/template/db_readme.md new file mode 100644 index 0000000..5a8e166 --- /dev/null +++ b/code-generator/src/main/resources/template/db_readme.md @@ -0,0 +1,19 @@ +## ${dbname}.${table_name} + +### `${table_comment}` + +> 表信息 + +| 属性 | 内容 | +| --- | --- | +| table_collation | ${table_collation} | +| engine | ${engine} | + +> 表结构 + +| 说明 | 字段名 | 字段类型 | 主键 | 允许为空 | 默认值 | 字符集 | 排序规则 | +| --- | --- | --- | --- | --- | --- | --- | --- | +<#list columnList as item> +| ${item.column_comment} | ${item.column_name} | ${item.column_type} | ${item.column_key} | ${item.is_nullable} | ${item.column_default} | ${item.character_set_name} | ${item.collation_name} + + diff --git a/code-generator/src/main/resources/template/db_tables_readme.md b/code-generator/src/main/resources/template/db_tables_readme.md new file mode 100644 index 0000000..4c27eb3 --- /dev/null +++ b/code-generator/src/main/resources/template/db_tables_readme.md @@ -0,0 +1,10 @@ +## ${dbname} 数据库 + +> 表格清单 + +| 表名 | 排序规则 | 引擎 | 说明 | +| --- | --- | --- | --- | +<#list tableList as item> +| [${item.table_name}](readme/db_${item.table_name}.md) | ${item.table_collation} | ${item.engine} | ${item.table_comment} | + + diff --git a/code-generator/src/main/resources/template/inteface_tables_readme.md b/code-generator/src/main/resources/template/inteface_tables_readme.md new file mode 100644 index 0000000..7719c53 --- /dev/null +++ b/code-generator/src/main/resources/template/inteface_tables_readme.md @@ -0,0 +1,44 @@ +**简要描述:** + +- ${table_comment} +- [${table_comment}](readme/ ${filename}) + +**请求URL:** +- ` /mj/${table_name}/select_page ` + +**请求方式:** +- POST + +**参数:** + +|参数名|类型|说明| +|:---- |:---|:----- |----- +<#list columnList as item> +| ${item.column_name} | ${item.column_type} | ${item.column_comment} | + +| pageIndex | int | 页数 | +| pageSize | int | 条数 | + + + + + **返回示例** +``` +{ + "data": { + "data": [ + { + <#list columnList as item> + "${item.column_name}":"test"(${item.column_comment}) + + } + ], + "pageCount": 1, + "pageIndex": 1, + "pageSize": 10, + "rowCount": 2(总数) + }, + "msg": "success", + "status": 10200 +} +``` diff --git a/code-generator/src/main/resources/template/mapper.ftl b/code-generator/src/main/resources/template/mapper.ftl new file mode 100644 index 0000000..f12c692 --- /dev/null +++ b/code-generator/src/main/resources/template/mapper.ftl @@ -0,0 +1,117 @@ + + + + + + + + + + + + + <#list columnList as item> + and a.${item.column_name} = ${"#"}{${item.column_name}} + + + <#list columnList as item> + and a.${item.column_name} like concat('%',${"#"}{like_${item.column_name}},'%') + + + + + + + + + + + + insert into ${table_name}( + + <#list columnList as item> + ${item.column_name}, + + ) + values( + + <#list columnList as item> + ${"#"}{${item.column_name}}, + + + ) + + + + + update ${table_name} + + <#list columnList as item> + <#if item.column_key?? && item.column_key!="PRI" || item.column_name?? && item.column_name != "id"> + ${item.column_name} = ${"#"}{${item.column_name}}, + + + + + <#list columnList as item> + and ${item.column_name} = ${"#"}{where_${item.column_name}} + + + + + + + delete from ${table_name} a + + + + + + + + insert into ${table_name}(<#list columnList as item>${item.column_name}<#if item_has_next>,) + values + + (<#list columnList as item>${"#"}{item.${item.column_name}}<#if item_has_next>,) + + + + + + update ${table_name} + + <#list columnList as item> + <#if item.column_key?? && item.column_key!="PRI" && item.column_name?? && item.column_name != "id" && item.column_name!="createtime"> + ${item.column_name}=${"#"}{item.${item.column_name}}, + + + + where id=${"#"}{item.id} + + + + + delete from ${table_name} where id in ( + + ${"#"}{item} + + ) + + \ No newline at end of file diff --git a/code-generator/src/main/resources/template/mapper.ftl.backup b/code-generator/src/main/resources/template/mapper.ftl.backup new file mode 100644 index 0000000..a37a436 --- /dev/null +++ b/code-generator/src/main/resources/template/mapper.ftl.backup @@ -0,0 +1,140 @@ + + + + + + + + + + + + ,(select name from zonepubinfo zp where 1=1 and zp.pubcode = a.gldw ) as gldwname + ,(select name from zoneadmin zd where 1=1 and zd.id = a.xzqh ) as xzqhname + + + + + <#list columnList as item> + <#assign age='${item.column_name}'> + <#if (age=='gldw')> + + and a.gldw in ( + + <#noparse> #{item} + + ) + + <#else> + and a.${item.column_name} = ${"#"}{${item.column_name}} + + + + + <#list columnList as item> + and a.${item.column_name} like concat('%',${"#"}{like_${item.column_name}},'%') + + + + + + + + + + + + insert into ${table_name}( + + <#list columnList as item> + ${item.column_name}, + + ) + values( + + <#list columnList as item> + ${"#"}{${item.column_name}}, + + + ) + + + + + update ${table_name} + + <#list columnList as item> + <#if item.column_key?? && item.column_key!="PRI" || item.column_name?? && item.column_name != "id"> + ${item.column_name} = ${"#"}{${item.column_name}}, + + + + + <#list columnList as item> + and ${item.column_name} = ${"#"}{where_${item.column_name}} + + + + + + + delete from ${table_name} a + + + + + + + + insert into ${table_name}(<#list columnList as item>${item.column_name}<#if item_has_next>,) + values + + (<#list columnList as item>${"#"}{item.${item.column_name}}<#if item_has_next>,) + + + + + + update ${table_name} + + <#list columnList as item> + <#if item.column_key?? && item.column_key!="PRI" && item.column_name?? && item.column_name != "id" && item.column_name!="createtime"> + ${item.column_name}=${"#"}{item.${item.column_name}}, + + + + where id=${"#"}{item.id} + + + + + delete from ${table_name} where id in ( + + ${"#"}{item} + + ) + + \ No newline at end of file diff --git a/code-generator/src/main/resources/template/service.ftl b/code-generator/src/main/resources/template/service.ftl new file mode 100644 index 0000000..bc97fac --- /dev/null +++ b/code-generator/src/main/resources/template/service.ftl @@ -0,0 +1,12 @@ +package com.qmrz.service; + +import java.util.List; +import java.util.Map; + +/** + * ${table_name},${table_comment} + * Automatic generation + */ +public interface ${table_name2}Service extends BaseService { + +} diff --git a/code-generator/src/main/resources/template/serviceImpl.ftl b/code-generator/src/main/resources/template/serviceImpl.ftl new file mode 100644 index 0000000..7046868 --- /dev/null +++ b/code-generator/src/main/resources/template/serviceImpl.ftl @@ -0,0 +1,22 @@ +package com.qmrz.service.impl; + +import com.qmrz.service.${table_name2}Service; +import com.qmrz.utils.MapUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +/** + * ${table_name},${table_comment} + * Automatic generation + */ +@Slf4j +@Service +public class ${table_name2}ServiceImpl extends BaseServiceImpl implements ${table_name2}Service { + public ${table_name2}ServiceImpl(){ + super("${table_name}"); + } +} + diff --git a/code-generator/src/test/TestCodeGenerator.java b/code-generator/src/test/TestCodeGenerator.java new file mode 100644 index 0000000..de38aea --- /dev/null +++ b/code-generator/src/test/TestCodeGenerator.java @@ -0,0 +1,89 @@ +import com.qmrz.CodeGenerator; +import com.qmrz.generator.*; +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@Slf4j +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = CodeGenerator.class) +public class TestCodeGenerator { + private String dbname="qmrzga-dev"; + /** + * 生成所有 + */ + @Test + public void generatorAll() { + readme(); + mapper(); + service(); + serviceImpl(); + controller(); + interface2(); + } + + + /** + * readme 生成 + */ + @Test + public void readme() { + DBReadmeGenerator generator = new DBReadmeGenerator(dbname); + generator.generator(); + } + + /** + * readme 生成 + */ + @Test + public void interface2() { + InterfaceReadmeGenerator generator = new InterfaceReadmeGenerator(dbname); + generator.generator(); + } + /** + * mapper 生成 + */ + @Test + public void mapper() { + MapperGenerator generator = new MapperGenerator(dbname); + generator.generator(); + } + + /** + * service 生成 + */ + @Test + public void service() { + ServiceGenerator generator = new ServiceGenerator(dbname); + generator.generator(); + } + + /** + * serviceImpl 生成 + */ + @Test + public void serviceImpl() { + ServiceImplGenerator generator = new ServiceImplGenerator(dbname); + generator.generator(); + } + + /** + * controller 生成 + */ + @Test + public void controller() { + ControllerGenerator generator = new ControllerGenerator(dbname); + generator.generator(); + } + + /** + * api_sync 同步 + */ + @Test + public void api_sync() { + ApiSyncGenerator generator = new ApiSyncGenerator(dbname); + generator.generator(); + } +} diff --git a/common/pom.xml b/common/pom.xml new file mode 100644 index 0000000..3607bd8 --- /dev/null +++ b/common/pom.xml @@ -0,0 +1,26 @@ + + + + codeGenerate + com.qmrz + 1.0 + + 4.0.0 + + common + + jar + + + org.apache.poi + poi + 3.9 + + + + + + + \ No newline at end of file diff --git a/common/src/main/java/com/qmrz/BaseAdminController.java b/common/src/main/java/com/qmrz/BaseAdminController.java new file mode 100644 index 0000000..e8dda8b --- /dev/null +++ b/common/src/main/java/com/qmrz/BaseAdminController.java @@ -0,0 +1,11 @@ +package com.qmrz; + +import com.qmrz.config.SysInfo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; + +@Slf4j +public class BaseAdminController { + @Autowired + protected SysInfo sysInfo; +} diff --git a/common/src/main/java/com/qmrz/admin/AdminLogin.java b/common/src/main/java/com/qmrz/admin/AdminLogin.java new file mode 100644 index 0000000..280ae12 --- /dev/null +++ b/common/src/main/java/com/qmrz/admin/AdminLogin.java @@ -0,0 +1,99 @@ +package com.qmrz.admin; + +import com.qmrz.constants.ConstantValue; +import com.qmrz.dto.SecurityAdminDTO; +import com.qmrz.exception.ABException; +import com.qmrz.utils.Session; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.subject.Subject; + +/** + * 管理员登录信息获取 + */ +public class AdminLogin { + public static final AdminLogin instance = new AdminLogin(); + + /** + * 获取管理员登录信息 + * + * @return + */ +// public AdminLoginInfo getAdminInfo() { +// AdminLoginInfo info = Session.getSession("admininfo"); +// return info; +// } + public SecurityAdminDTO getAdminInfo() { + Subject currentUser = SecurityUtils.getSubject(); + SecurityAdminDTO info = (SecurityAdminDTO) currentUser.getPrincipal(); + + return info; + } + + public Boolean isSuper() { + return ConstantValue.ONE.equals(getAdminInfo().getIssuper()); + } + + /** + * 获取管理员名称 + * + * @return + */ +// public String getAdminName() { +// AdminLoginInfo info = getAdminInfo(); +// if (info == null) { +// return "未登录"; +// } +// return info.getAdminname(); +// } + public String getAdminName() { + Subject currentUser = SecurityUtils.getSubject(); + if (!currentUser.isAuthenticated()) { + return "未登录"; + } + return ((SecurityAdminDTO) currentUser.getPrincipal()).getUsername(); + } + + /** + * 验证用户是否登录 + * + * @return + */ +// public boolean isLogin() { +// AdminLoginInfo info = getAdminInfo(); +// if (info == null) { +// return false; +// } +// return info.getAdminid() > 0; +// } + public boolean isLogin() { + Subject currentUser = SecurityUtils.getSubject(); + return currentUser.isAuthenticated(); + } + + public static final String CustomerInfo_SessionName = "admin_customer_info"; + + public static CustomerInfo getCustomerInfo() { + CustomerInfo info = Session.getSession(CustomerInfo_SessionName); + if (info == null) { + throw new ABException("客户标识不存在"); + } + + if (info.getCustomerID() == null || info.getCustomerDir() == null) { + throw new ABException("客户id 或 dir为空"); + } + + return info; + } + + public static Integer getCustomerID() { + return getCustomerInfo().getCustomerID(); + } + + public static void setCustomInfo(CustomerInfo customInfo){ + if (customInfo.getCustomerID() == null || customInfo.getCustomerDir() == null) { + throw new ABException("客户id 或 dir为空"); + } + + Session.setSession(CustomerInfo_SessionName,customInfo); + } +} diff --git a/common/src/main/java/com/qmrz/admin/AdminLoginInfo.java b/common/src/main/java/com/qmrz/admin/AdminLoginInfo.java new file mode 100644 index 0000000..7297dd3 --- /dev/null +++ b/common/src/main/java/com/qmrz/admin/AdminLoginInfo.java @@ -0,0 +1,12 @@ +package com.qmrz.admin; + +import lombok.Data; + +/** + * 管理员登录信息 + */ +@Data +public class AdminLoginInfo { + private int adminid; + private String adminname; +} diff --git a/common/src/main/java/com/qmrz/admin/CustomerInfo.java b/common/src/main/java/com/qmrz/admin/CustomerInfo.java new file mode 100644 index 0000000..93fef8f --- /dev/null +++ b/common/src/main/java/com/qmrz/admin/CustomerInfo.java @@ -0,0 +1,14 @@ +package com.qmrz.admin; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.io.Serializable; + +@Data +@AllArgsConstructor +public class CustomerInfo implements Serializable { + private static final long serialVersionUID = -1959344102914768364L; + private Integer customerID; + private String customerDir; +} diff --git a/common/src/main/java/com/qmrz/config/Config.java b/common/src/main/java/com/qmrz/config/Config.java new file mode 100644 index 0000000..0c67b4f --- /dev/null +++ b/common/src/main/java/com/qmrz/config/Config.java @@ -0,0 +1,75 @@ +package com.qmrz.config; + +import com.github.pagehelper.PageInterceptor; +import com.qmrz.mybatis.MapperScannerConfigurer; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.SqlSessionTemplate; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; + +/** + * 初始配置 + */ +@Slf4j +@Configuration +public class Config { + public Config() { + log.info("------------ Config"); + } + + /** + * 配置数据源 + * + * @param dbInfo 数据库配置信息 + * @return + */ + @Bean + public DataSource dataSource(ConfigDBInfo dbInfo) { + log.info("------------ dataSource"); + log.info(dbInfo.toString()); + return ConfigDBUtils.getDruid(dbInfo); + } + + /** + * 利用SqlSessionFactoryBean,绑定mapper(xml)位置 + * + * @param dataSource 数据源 + * @return + */ + @Bean("SqlSessionFactory") + public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource,PageInterceptor pageHelper) throws Exception { + log.info("------------ SqlSessionFactoryBean"); + SqlSessionFactoryBean sqlSessionFactoryBean = + ConfigDBUtils.getSqlSessionFactoryBean(dataSource, "classpath*:mapper/*.xml",pageHelper); + + return sqlSessionFactoryBean; + } + + @Bean("sqlSessionTemplate") + public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { + log.info("------------ sqlSessionTemplate"); + SqlSessionTemplate s = new SqlSessionTemplate(sqlSessionFactory); + return s; + } + + /** + * mapper配置扫描并绑定 + * + * @return + */ + @Bean + public MapperScannerConfigurer mapperScannerConfigurer() { + log.info("------------ MapperScannerConfigurer"); + //SqlSessionFactory名称即是SqlSessionFactoryBean的指定bean名 + return ConfigDBUtils.getMapperScannerConfigurer("SqlSessionFactory", "com.qmrz.domain.mapper"); + } + + @Bean + public PageInterceptor pageHelper() { + return ConfigDBUtils.pageHelper(); + } +} diff --git a/common/src/main/java/com/qmrz/config/ConfigDBInfo.java b/common/src/main/java/com/qmrz/config/ConfigDBInfo.java new file mode 100644 index 0000000..2e289bc --- /dev/null +++ b/common/src/main/java/com/qmrz/config/ConfigDBInfo.java @@ -0,0 +1,24 @@ +package com.qmrz.config; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 数据库配置信息 + */ +@Slf4j +@Component +@Data +@ConfigurationProperties(prefix = "db") +public class ConfigDBInfo { + private String driver; + private String url; + private String username; + private String password; + + public ConfigDBInfo() { + log.info("------ ConfigDBInfo"); + } +} diff --git a/common/src/main/java/com/qmrz/config/ConfigDBUtils.java b/common/src/main/java/com/qmrz/config/ConfigDBUtils.java new file mode 100644 index 0000000..31e42ba --- /dev/null +++ b/common/src/main/java/com/qmrz/config/ConfigDBUtils.java @@ -0,0 +1,149 @@ +package com.qmrz.config; + + +import com.alibaba.druid.filter.Filter; +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.wall.WallConfig; +import com.alibaba.druid.wall.WallFilter; +import com.github.pagehelper.PageInterceptor; +import com.qmrz.mybatis.MapperScannerConfigurer; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.session.Configuration; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.FileSystemXmlApplicationContext; + +import javax.sql.DataSource; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +/** + * 数据库配置工具 + */ +@Slf4j +public class ConfigDBUtils { + /** + * 生成数据源 + * + * @param info + * @return + */ + public static DataSource getDruid(ConfigDBInfo info) { + log.info("Create DruidDataSource:" + info.getUrl()); + + DruidDataSource dds = new DruidDataSource(); + dds.setUrl(info.getUrl()); + dds.setUsername(info.getUsername()); + dds.setPassword(info.getPassword()); + dds.setDriverClassName(info.getDriver()); + dds.setInitialSize(0);//初始化连接大小 + dds.setMaxActive(3000);//连接池最大使用连接数量 + dds.setMinIdle(0);//连接池最小空闲 + dds.setMaxWait(60000);//获取连接最大等待时间 + dds.setValidationQuery("select 1");//验证数据库连接有效性,要求查询语句 + + WallConfig wallConfig = new WallConfig(); + wallConfig.setMultiStatementAllow(true); + + WallFilter wallFilter = new WallFilter(); + wallFilter.setConfig(wallConfig); + List filters = new ArrayList<>(); + filters.add(wallFilter); + dds.setProxyFilters(filters); + + //建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 + dds.setTestWhileIdle(true); + + //申请连接时执行validationQuery检测连接是否有效,配置true会降低性能。 + dds.setTestOnBorrow(false); + + //归还连接时执行validationQuery检测连接是否有效,配置true会降低性能 + dds.setTestOnReturn(false); + + //配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + dds.setTimeBetweenEvictionRunsMillis(60000); + + //配置一个连接在池中最小生存的时间,单位是毫秒 + dds.setMinEvictableIdleTimeMillis(25200000); + + //对于长时间不使用的连接强制关闭 + dds.setRemoveAbandoned(true); + + //关闭超过30分钟的空闲连接,1800秒,也就是30分钟 + dds.setRemoveAbandonedTimeout(1800); + + //关闭abanded连接时输出错误日志 + dds.setLogAbandoned(true); + + //设置批量更新 + + //监控数据库 + //dds.setFilters("mergeStat"); + try { + dds.setFilters("stat,wall"); + } catch (SQLException e) { + log.info("error:" + e.getMessage()); + // TODO Auto-generated catch block + e.printStackTrace(); + } + return dds; + } + + + /** + * 使用SqlSessionFactoryBean,扫描或绑定mapper(xml)位置 + * + * @param dataSource 数据源 + * @param mapperPath mapper(xml)位置 + */ + public static SqlSessionFactoryBean getSqlSessionFactoryBean(DataSource dataSource, String mapperPath, PageInterceptor pageHelper) { + SqlSessionFactoryBean s = new SqlSessionFactoryBean(); + s.setDataSource(dataSource); + + s.setPlugins(new Interceptor[]{pageHelper}); + ApplicationContext ctx = new FileSystemXmlApplicationContext(); + + try { + Configuration c = new Configuration(); + c.setCallSettersOnNulls(true); + s.setConfiguration(c); + s.setMapperLocations(ctx.getResources(mapperPath)); + } catch (IOException e) { + e.printStackTrace(); + } + + return s; + } + + public static PageInterceptor pageHelper() { + PageInterceptor pageHelper = new PageInterceptor(); + Properties p = new Properties(); + p.setProperty("offsetAsPageNum", "true"); + p.setProperty("rowBoundsWithCount", "true"); + p.setProperty("reasonable", "true"); +// p.setProperty("dialect", "mysql"); + pageHelper.setProperties(p); + return pageHelper; + } + + /** + * 使用MapperScannerConfigurer,扫描或绑定 mapper接口位置,并与xml文件映射生产相应实例 + * + * @param sqlSessionFactoryBean + * @param packageName + */ + public static MapperScannerConfigurer getMapperScannerConfigurer(String sqlSessionFactoryBean, String packageName) { + MapperScannerConfigurer m = new MapperScannerConfigurer(); + //包名:指定mapper接口所在包位置 + m.setBasePackage(packageName); + + //SqlSessionFactoryBea的名称,用与mapper的接口和xml的映射 + m.setSqlSessionFactoryBeanName(sqlSessionFactoryBean); + + return m; + } +} diff --git a/common/src/main/java/com/qmrz/config/ConfigUploadFileInfo.java b/common/src/main/java/com/qmrz/config/ConfigUploadFileInfo.java new file mode 100644 index 0000000..2db2a65 --- /dev/null +++ b/common/src/main/java/com/qmrz/config/ConfigUploadFileInfo.java @@ -0,0 +1,18 @@ +package com.qmrz.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 数据库配置信息 + */ +@Component +@Data +@ConfigurationProperties(prefix = "uploadfile") +public class ConfigUploadFileInfo { + private Long size;//byte + private String path; + private int picMaxWidth;//px + private int picMaxHeight;//px +} diff --git a/common/src/main/java/com/qmrz/config/SecurityConfig.java b/common/src/main/java/com/qmrz/config/SecurityConfig.java new file mode 100644 index 0000000..f0a2622 --- /dev/null +++ b/common/src/main/java/com/qmrz/config/SecurityConfig.java @@ -0,0 +1,15 @@ +package com.qmrz.config; + +//@Configuration +//@EnableWebSecurity +public class SecurityConfig { +// @Override +// protected void configure(HttpSecurity http) throws Exception { +// http.csrf().disable(); +// http.authorizeRequests().antMatchers("/").permitAll() +// .and() +// .headers().frameOptions().disable(); +// +// +// } +} diff --git a/common/src/main/java/com/qmrz/config/SysInfo.java b/common/src/main/java/com/qmrz/config/SysInfo.java new file mode 100644 index 0000000..96c49a9 --- /dev/null +++ b/common/src/main/java/com/qmrz/config/SysInfo.java @@ -0,0 +1,79 @@ +package com.qmrz.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@Data +@ConfigurationProperties(prefix = "sys") +public class SysInfo { + /** 站点名称 */ + private String name; + + /** + * token密钥 + */ + private String policeSecret; + + /** + * 过期毫秒数 + */ + private Long policeExpire; + + /** + * wxapp表id为wxappid的做为系统公众号 + */ + private Integer wxappid; + + /** + * 微信公众号域名 + */ + private String wxdomain; + + /** + * 阿里短信应用id + */ + private Integer alismsid; + + /** + * 微信支付回调地址 + */ + private String paynotifyurl; + + /** + * 订单生成的机器 IP + */ + private String payip; + + + /** + * shiro session超时时间1天 + */ + private Integer globalSessionTimeout; + + /** + * shiro 缓存前缀 + */ + private String shiroCachePrefix; + + /** + * 是否开启api 数据同步 + */ + private Boolean openSyncApi; + + /** + * 是否开启 自动分派 + */ + private Boolean openBatchAssign; + + /** + * 数据库名 + */ + private String dbname; + + /** + * 数据同步地址 + */ + private String syncapiurl; +} diff --git a/common/src/main/java/com/qmrz/constants/ABMessage.java b/common/src/main/java/com/qmrz/constants/ABMessage.java new file mode 100644 index 0000000..98f9593 --- /dev/null +++ b/common/src/main/java/com/qmrz/constants/ABMessage.java @@ -0,0 +1,6 @@ +package com.qmrz.constants; + +public class ABMessage { + public static final String test = "注意,是测试数据,接口对接中"; + public static final String test2 = "注意,是测试数据,暂时都返回固定站点信息"; +} diff --git a/common/src/main/java/com/qmrz/constants/ConstantValue.java b/common/src/main/java/com/qmrz/constants/ConstantValue.java new file mode 100644 index 0000000..5098523 --- /dev/null +++ b/common/src/main/java/com/qmrz/constants/ConstantValue.java @@ -0,0 +1,7 @@ +package com.qmrz.constants; + +public class ConstantValue { + public static final Integer ZERO = 0; + public static final Integer ONE = 1; + public static final Integer TWO = 2; +} diff --git a/common/src/main/java/com/qmrz/dto/PageMapDTO.java b/common/src/main/java/com/qmrz/dto/PageMapDTO.java new file mode 100644 index 0000000..fcb9425 --- /dev/null +++ b/common/src/main/java/com/qmrz/dto/PageMapDTO.java @@ -0,0 +1,33 @@ +package com.qmrz.dto; + +import com.qmrz.utils.Fn; +import java.util.HashMap; + +/** + * 通用参数接收模型(可扩展) + */ +public class PageMapDTO extends HashMap { + /** + * 页码 默认第1页 + * @return + */ + public int getPageIndex() { + int pageIdnex = Fn.toInt(this.get("pageIndex")); + if (pageIdnex <= 0) { + pageIdnex = 1; + } + return pageIdnex; + } + + /** + * 每页记录数 默认每页20条 + * @return + */ + public int getPageSize(){ + int pageSize = Fn.toInt(this.get("pageSize")); + if (pageSize <= 0) { + pageSize = 20; + } + return pageSize; + } +} diff --git a/common/src/main/java/com/qmrz/dto/ParamCodeDTO.java b/common/src/main/java/com/qmrz/dto/ParamCodeDTO.java new file mode 100644 index 0000000..7500b6e --- /dev/null +++ b/common/src/main/java/com/qmrz/dto/ParamCodeDTO.java @@ -0,0 +1,19 @@ +package com.qmrz.dto; + +import lombok.Data; + +@Data +public class ParamCodeDTO { + private String code; + + public ParamCodeDTO() { + } + + public ParamCodeDTO(String code) { + this.code = code; + } + + public static ParamCodeDTO newdto(String code){ + return new ParamCodeDTO(code); + } +} diff --git a/common/src/main/java/com/qmrz/dto/ParamCustomer.java b/common/src/main/java/com/qmrz/dto/ParamCustomer.java new file mode 100644 index 0000000..cd6e145 --- /dev/null +++ b/common/src/main/java/com/qmrz/dto/ParamCustomer.java @@ -0,0 +1,19 @@ +package com.qmrz.dto; + +import com.qmrz.admin.AdminLogin; +import com.qmrz.exception.ABException; +import lombok.Data; + +@Data +public class ParamCustomer { + private Integer customerid = AdminLogin.getCustomerInfo().getCustomerID(); + + public ParamCustomer setCustomerid(Integer customerid){ + throw new ABException("customerid不允许set,请使用_set"); + } + + public ParamCustomer _setCustomerid(Integer customerid){ + this.customerid = customerid; + return this; + } +} diff --git a/common/src/main/java/com/qmrz/dto/ParamIDDTO.java b/common/src/main/java/com/qmrz/dto/ParamIDDTO.java new file mode 100644 index 0000000..2910cda --- /dev/null +++ b/common/src/main/java/com/qmrz/dto/ParamIDDTO.java @@ -0,0 +1,45 @@ +package com.qmrz.dto; + +import com.qmrz.admin.AdminLogin; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +@Data +@Slf4j +public class ParamIDDTO { + private Integer id; + private Integer customerid; + + public ParamIDDTO setCustomerid(Integer customerid) { + log.warn("customerid不允许set,请使用_set"); + return this; + } + + public ParamIDDTO _setCustomerid(Integer customerid) { + this.customerid = customerid; + return this; + } + + public ParamIDDTO() { + this.customerid = AdminLogin.getCustomerInfo().getCustomerID(); + } + + public ParamIDDTO(Integer id) { + this.id = id; + this.customerid = AdminLogin.getCustomerInfo().getCustomerID(); + } + + public ParamIDDTO(Integer id, Integer customerid) { + this.id = id; + this.customerid = customerid; + } + + public static ParamIDDTO newdto(Integer id) { + return new ParamIDDTO(id); + } + +// @Override +// public String toString() { +// return id.toString(); +// } +} diff --git a/common/src/main/java/com/qmrz/dto/ParamIDPageDTO.java b/common/src/main/java/com/qmrz/dto/ParamIDPageDTO.java new file mode 100644 index 0000000..36fe6be --- /dev/null +++ b/common/src/main/java/com/qmrz/dto/ParamIDPageDTO.java @@ -0,0 +1,29 @@ +package com.qmrz.dto; + +import lombok.Data; + +@Data +public class ParamIDPageDTO extends ParamPageDTO { + private Integer id; + + public ParamIDPageDTO() { + } + + public ParamIDPageDTO(Integer id) { + this.id = id; + } + + public ParamIDPageDTO(Integer id, ParamPageDTO pageDTO) { + this.id = id; + this.setPageIndex(pageDTO.getPageIndex()); + this.setPageSize(pageDTO.getPageSize()); + } + + public static ParamIDPageDTO newdto(Integer id) { + return new ParamIDPageDTO(id); + } + + public static ParamIDPageDTO newdto(Integer id, ParamPageDTO pageDTO) { + return new ParamIDPageDTO(id, pageDTO); + } +} diff --git a/common/src/main/java/com/qmrz/dto/ParamLongIDDTO.java b/common/src/main/java/com/qmrz/dto/ParamLongIDDTO.java new file mode 100644 index 0000000..e1d1a8e --- /dev/null +++ b/common/src/main/java/com/qmrz/dto/ParamLongIDDTO.java @@ -0,0 +1,20 @@ +package com.qmrz.dto; + +import lombok.Data; + +@Data +public class ParamLongIDDTO { + private Long id; + + public ParamLongIDDTO() { + } + + public ParamLongIDDTO(Long id) { + this.id = id; + } + + public static ParamLongIDDTO newdto(Long id){ + return new ParamLongIDDTO(id); + } + +} diff --git a/common/src/main/java/com/qmrz/dto/ParamMoneyDTO.java b/common/src/main/java/com/qmrz/dto/ParamMoneyDTO.java new file mode 100644 index 0000000..26fa166 --- /dev/null +++ b/common/src/main/java/com/qmrz/dto/ParamMoneyDTO.java @@ -0,0 +1,24 @@ +package com.qmrz.dto; + +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 金额 + */ +@Data +public class ParamMoneyDTO { + private BigDecimal money; + + public ParamMoneyDTO() { + } + + public ParamMoneyDTO(BigDecimal money) { + this.money = money; + } + + public static ParamMoneyDTO newdto(BigDecimal money){ + return new ParamMoneyDTO(money); + } +} diff --git a/common/src/main/java/com/qmrz/dto/ParamNameDTO.java b/common/src/main/java/com/qmrz/dto/ParamNameDTO.java new file mode 100644 index 0000000..1398676 --- /dev/null +++ b/common/src/main/java/com/qmrz/dto/ParamNameDTO.java @@ -0,0 +1,40 @@ +package com.qmrz.dto; + +import com.qmrz.admin.AdminLogin; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +@Data +@Slf4j +public class ParamNameDTO { + private String name; + private Integer customerid; + + public ParamNameDTO setCustomerid(Integer customerid){ + log.warn("customerid不允许set,请使用_set"); + return this; + } + + public ParamNameDTO _setCustomerid(Integer customerid){ + this.customerid = customerid; + return this; + } + + public ParamNameDTO() { + this.customerid = AdminLogin.getCustomerInfo().getCustomerID(); + } + + public ParamNameDTO(String name) { + this.name = name; + this.customerid = AdminLogin.getCustomerInfo().getCustomerID(); + } + + public ParamNameDTO(String name,Integer customerid) { + this.name = name; + this.customerid = customerid; + } + + public static ParamNameDTO newdto(String name) { + return new ParamNameDTO(name); + } +} diff --git a/common/src/main/java/com/qmrz/dto/ParamPageDTO.java b/common/src/main/java/com/qmrz/dto/ParamPageDTO.java new file mode 100644 index 0000000..dd37a0a --- /dev/null +++ b/common/src/main/java/com/qmrz/dto/ParamPageDTO.java @@ -0,0 +1,61 @@ +package com.qmrz.dto; + +import com.github.pagehelper.PageHelper; +import com.qmrz.admin.AdminLogin; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +/** + * 接收参数基础对象:含分页等属性 + */ +@Data +@Slf4j +public class ParamPageDTO { + /** + * 默认第1页 + */ + private int pageIndex = 1; + /** + * 默认20条每页 + */ + private int pageSize = 20; + +// private Integer customerid; + + public ParamPageDTO() { +// this.customerid = AdminLogin.getCustomerInfo().getCustomerID(); + } + + public ParamPageDTO(Integer customerid) { +// this.customerid = customerid; + } + + public ParamPageDTO(Integer customerid, Integer pageIndex, Integer pageSize) { +// this.customerid = customerid; + if (pageIndex <= 0) { + pageIndex = 1; + } + this.pageIndex = pageIndex; + if (pageSize <= 0) { + pageSize = 20; + } + this.pageSize = pageSize; + } + + public ParamPageDTO setCustomerid(Integer customerid) { + log.warn("customerid不允许set,请使用_set"); + return this; + } + + public ParamPageDTO _setCustomerid(Integer customerid) { +// this.customerid = customerid; + return this; + } + + /** + * 使用分页mapper时,请调用此方法 + */ + public void startPage() { + PageHelper.startPage(pageIndex, pageSize); + } +} diff --git a/common/src/main/java/com/qmrz/dto/ParamTypeDTO.java b/common/src/main/java/com/qmrz/dto/ParamTypeDTO.java new file mode 100644 index 0000000..b0f14ca --- /dev/null +++ b/common/src/main/java/com/qmrz/dto/ParamTypeDTO.java @@ -0,0 +1,19 @@ +package com.qmrz.dto; + +import lombok.Data; + +@Data +public class ParamTypeDTO { + private Integer type; + + public ParamTypeDTO() { + } + + public ParamTypeDTO(Integer type) { + this.type = type; + } + + public static ParamTypeDTO newdto(Integer type){ + return new ParamTypeDTO(type); + } +} diff --git a/common/src/main/java/com/qmrz/dto/SecurityAdminDTO.java b/common/src/main/java/com/qmrz/dto/SecurityAdminDTO.java new file mode 100644 index 0000000..40a8bec --- /dev/null +++ b/common/src/main/java/com/qmrz/dto/SecurityAdminDTO.java @@ -0,0 +1,35 @@ +package com.qmrz.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; + +@Data +public class SecurityAdminDTO implements Serializable { + private static final long serialVersionUID = 1922126787657987938L; + private Integer id; + private String username; + private String password; + + /** + * 角色列表 + */ + private HashMap> roles; + + /** + * 权限列表 + */ + private List funs; + /** + * 是否超级管理员 + */ + private Integer issuper; + + private Integer islock; + + private Long addtime; + + private Long updatetime; +} diff --git a/common/src/main/java/com/qmrz/dto/TParamIDDTO.java b/common/src/main/java/com/qmrz/dto/TParamIDDTO.java new file mode 100644 index 0000000..674bfdc --- /dev/null +++ b/common/src/main/java/com/qmrz/dto/TParamIDDTO.java @@ -0,0 +1,25 @@ +package com.qmrz.dto; + +import lombok.Data; + +@Data +public class TParamIDDTO { + private Integer id; + private T model; + + public TParamIDDTO() { + } + + public TParamIDDTO(Integer id) { + this.id = id; + } + + public static TParamIDDTO newdto(Integer id){ + return new TParamIDDTO(id); + } + +// @Override +// public String toString() { +// return id.toString(); +// } +} diff --git a/common/src/main/java/com/qmrz/exception/ABException.java b/common/src/main/java/com/qmrz/exception/ABException.java new file mode 100644 index 0000000..7bc628f --- /dev/null +++ b/common/src/main/java/com/qmrz/exception/ABException.java @@ -0,0 +1,53 @@ +package com.qmrz.exception; + +import com.qmrz.utils.RDCode; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ABException extends RuntimeException { + private RDCode code; + + public ABException() { + super(RDCode.exception.getMessage()); + this.code = RDCode.exception; + log(); + } + + public ABException(String msg, Throwable cause) { + super(msg, cause); + this.code = RDCode.exception; + log(); + } + + public ABException(RDCode code, String msg) { + super(msg); + this.code = code; + log(); + } + + public ABException(RDCode code, String msg, Throwable cause) { + super(msg, cause); + this.code = code; + log(); + } + + public ABException(String msg) { + super(msg); + this.code = RDCode.exception; + log(); + } + + public ABException(RDCode code) { + super(code.getMessage()); + this.code = code; + log(); + } + + public RDCode getCode() { + return code; + } + + private void log() { + log.error(this.getClass().getName() + ":" + this.code.getState() + ":" + this.getMessage()); + } +} diff --git a/common/src/main/java/com/qmrz/exception/FailureException.java b/common/src/main/java/com/qmrz/exception/FailureException.java new file mode 100644 index 0000000..6c443c6 --- /dev/null +++ b/common/src/main/java/com/qmrz/exception/FailureException.java @@ -0,0 +1,14 @@ +package com.qmrz.exception; + +import com.qmrz.utils.RDCode; +import lombok.extern.slf4j.Slf4j; + +/** + * 失败异常 + */ +@Slf4j +public class FailureException extends ABException { + public FailureException(String msg) { + super(RDCode.failure, msg); + } +} diff --git a/common/src/main/java/com/qmrz/exception/GlobalControllerException.java b/common/src/main/java/com/qmrz/exception/GlobalControllerException.java new file mode 100644 index 0000000..9ff8bff --- /dev/null +++ b/common/src/main/java/com/qmrz/exception/GlobalControllerException.java @@ -0,0 +1,66 @@ +package com.qmrz.exception; + +import com.qmrz.utils.RD; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindException; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +@ControllerAdvice +public class GlobalControllerException extends ResponseEntityExceptionHandler { + + private ObjectError error; + + @Override + protected ResponseEntity handleBindException(BindException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { + log.info("------ GlobalControllerException -----"); + //ex.printStackTrace(); + //System.out.println("====== GlobalControllerException ====="); + + List list = ex.getAllErrors(); + + if (list.size() > 0) { + return handleExceptionInternal(ex, RD.failure(list.get(0).getDefaultMessage()), headers, status, request); + } + + return handleExceptionInternal(ex, RD.failure(ex.getMessage()), headers, status, request); + } + + @Override + protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { + System.out.println("------ MethodArgumentExceptionHandler -----"); + //ex.printStackTrace(); + //System.out.println("====== MethodArgumentExceptionHandler ====="); + + List list = ex.getBindingResult().getAllErrors(); + + if (list.size() > 0) { +// return handleExceptionInternal(ex, RD.failure(list.get(0).getDefaultMessage()), headers, status, request); + Map result = new HashMap<>(); + for (ObjectError error : list) { + if (error instanceof FieldError) { + FieldError err = (FieldError) error; + result.put(err.getField(), err.getDefaultMessage()); + } + } + + if (result.size() > 0) { + return handleExceptionInternal(ex, RD.failureByForm("操作失败", result), headers, HttpStatus.OK, request); + } + } + + return handleExceptionInternal(ex, RD.failure(ex.getMessage()), headers, status, request); + } +} diff --git a/common/src/main/java/com/qmrz/exception/GlobalSpringException.java b/common/src/main/java/com/qmrz/exception/GlobalSpringException.java new file mode 100644 index 0000000..aed587f --- /dev/null +++ b/common/src/main/java/com/qmrz/exception/GlobalSpringException.java @@ -0,0 +1,36 @@ +package com.qmrz.exception; + +import com.qmrz.utils.RD; +import com.qmrz.utils.Web; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * 全局 spring 异常捕获 + */ +@Slf4j +public class GlobalSpringException implements HandlerExceptionResolver { + @Override + public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { + log.info("GlobalSpringException:" + ex.getMessage()); + if (ex instanceof org.apache.shiro.authz.UnauthorizedException) { + Web.printRD(response, RD.notpermission()); + return new ModelAndView(); + } else if (ex instanceof ABException) { + ABException ab = (ABException) ex; + Web.printRD(response, RD.create(ab.getCode(), ab.getMessage(), null)); + return new ModelAndView(); + } else { + Web.printRD(response, RD.exception(ex.getMessage()+ ex.getClass().getName())); + log.error(RD.exception(ex.getMessage() + ex.getClass().getName()).toString()); + ex.printStackTrace(); + return new ModelAndView(); + } + +// return null; + } +} diff --git a/common/src/main/java/com/qmrz/exception/NotPermissionException.java b/common/src/main/java/com/qmrz/exception/NotPermissionException.java new file mode 100644 index 0000000..99f3fbb --- /dev/null +++ b/common/src/main/java/com/qmrz/exception/NotPermissionException.java @@ -0,0 +1,16 @@ +package com.qmrz.exception; + +import com.qmrz.utils.RDCode; + +/** + * 无权限异常 + */ +public class NotPermissionException extends ABException { + public NotPermissionException() { + super(RDCode.nopermission); + } + + public NotPermissionException(String msg) { + super(RDCode.nopermission,msg); + } +} diff --git a/common/src/main/java/com/qmrz/exception/PoliceNotLoginException.java b/common/src/main/java/com/qmrz/exception/PoliceNotLoginException.java new file mode 100644 index 0000000..aec0b13 --- /dev/null +++ b/common/src/main/java/com/qmrz/exception/PoliceNotLoginException.java @@ -0,0 +1,12 @@ +package com.qmrz.exception; + +import com.qmrz.utils.RDCode; + +/** + * 民警未登录或超时 + */ +public class PoliceNotLoginException extends ABException { + public PoliceNotLoginException() { + super(RDCode.notlogin); + } +} diff --git a/common/src/main/java/com/qmrz/exception/UserNotLoginException.java b/common/src/main/java/com/qmrz/exception/UserNotLoginException.java new file mode 100644 index 0000000..c120d8a --- /dev/null +++ b/common/src/main/java/com/qmrz/exception/UserNotLoginException.java @@ -0,0 +1,12 @@ +package com.qmrz.exception; + +import com.qmrz.utils.RDCode; + +/** + * 用户未登录 + */ +public class UserNotLoginException extends ABException { + public UserNotLoginException() { + super(RDCode.notlogin); + } +} diff --git a/common/src/main/java/com/qmrz/exception/WXUserNotAuthorizationException.java b/common/src/main/java/com/qmrz/exception/WXUserNotAuthorizationException.java new file mode 100644 index 0000000..6356a5a --- /dev/null +++ b/common/src/main/java/com/qmrz/exception/WXUserNotAuthorizationException.java @@ -0,0 +1,12 @@ +package com.qmrz.exception; + +import com.qmrz.utils.RDCode; + +/** + * 微信用户未授权或超时 + */ +public class WXUserNotAuthorizationException extends ABException { + public WXUserNotAuthorizationException() { + super(RDCode.notauthorization); + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/BasePO.java b/common/src/main/java/com/qmrz/mybatis/BasePO.java new file mode 100644 index 0000000..6c1d975 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/BasePO.java @@ -0,0 +1,274 @@ +package com.qmrz.mybatis; + +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; +import com.qmrz.dto.ParamPageDTO; +import com.qmrz.exception.ABException; +import com.qmrz.mybatis.service.BaseService; +import com.qmrz.mybatis.sql.BaseWrapper; +import com.qmrz.mybatis.sql.sqlnode.UpdateParam; +import com.qmrz.utils.PageData; +import com.qmrz.utils.SpringContextUtil; +import lombok.extern.slf4j.Slf4j; +import org.mybatis.spring.SqlSessionTemplate; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +@Slf4j +public class BasePO implements BaseService { + SqlSessionTemplate sqlTemp; + POUtil poUtil; + private POProxy poProxy; + + public void _setPoProxy(POProxy poProxy) { + this.poProxy = poProxy; + } + + public POProxy _getProxy() { + return poProxy; + } + + public void _setPoUtil(POUtil poUtil) { + this.poUtil = poUtil; + } + + public BasePO() { + this.sqlTemp = SpringContextUtil.getBean(SqlSessionTemplate.class); + } + + private String getMSID(String methodName) { + String claName; + if (poProxy != null) { + claName = poProxy.getClassPO().getName(); + } else { + claName = this.getClass().getName(); + } + return claName + "_" + methodName + "_ActiveRecord"; + } + + private Map toMap(Object obj) { + return toMap(obj, true); + } + + private Map toMap(Object obj, boolean isContainKey) { + if (obj instanceof Map) { + return (Map) obj; + } + + if (obj instanceof BasePO) { + BasePO basePO = (BasePO) obj; + if (basePO._getProxy() == null) { + throw new ABException("请使用proxy()创建实体对象:" + this.getClass().getName()); +// return new POUtil(obj.getClass()).getMapNotNull(obj); + } else { + + Map result = basePO._getProxy().getSetList(); + if (!isContainKey) { + result.remove(poUtil.getPrimarykey().getFieldNameByDB()); + } + return result; + } + } else { + return poUtil.getParam(obj); + } + +// throw new ABException("非法参数"); + } + + private BasePO createProxy() { + poProxy = new POProxy(); + poUtil = new POUtil(this.getClass()); + + BasePO po = poProxy.getProxy(this.getClass()); + + po._setPoProxy(poProxy); + po._setPoUtil(poUtil); + return po; + } + + /** + * 创建代理对象 + * + * @return + */ + public T proxy() { + return (T) this.createProxy(); + } + + /** + * 创建代理对象,并初始化填充代理对象 + * + * @param object 将object属性填充到代理对象(即将非代理对象使用代理对象接管) + * @return + */ + public T proxy(Object object) { + return proxy(object, false); + } + + /** + * @param object + * @param isAllowNull 指定object里属性是否允许为空 + * @return + */ + public T proxy(Object object, boolean isAllowNull) { + BasePO po = this.createProxy(); + POUtil.fillNotNull(po, object, isAllowNull); + return (T) po; + } + + /** + * 创建代理对象,并初始化填充代理对象数据 + * + * @param object + * @param only 初始指定字段(初始化数据时,只填充在onlyFieldNameList里包含的字段) + * @return + */ + public T proxy(Object object, String... only) { + return proxy(object, false, only); + } + + public T proxy(Object object, boolean isAllowNull, String... only) { + BasePO po = this.createProxy(); + + //将object属性填充到代理对象(即将非代理对象使用代理对象接管) + POUtil.fillNotNull(po, object, only, isAllowNull); + return (T) po; + } + + @Override + public List selectWrapper(Consumer wrapper) { + return this.sqlTemp.selectList(getMSID("selectWrapper"), wrapper); + } + + @Override + public T selectOneWrapper(Consumer wrapper) { + List list = this.sqlTemp.selectList(getMSID("selectOneWrapper"), wrapper); + if (list.size() == 0) { + return null; + } + return list.get(0); + } + + @Override + public Integer updateWrapper(Object param, Consumer wrapper) { + return this.sqlTemp.update(getMSID("updateWrapper") + , new UpdateParam(toMap(param), wrapper)); + } + + public Integer update(Consumer wrapper) { + return this.sqlTemp.update(getMSID("updateWrapper") + , new UpdateParam(toMap(this), wrapper)); + } + + @Override + public Integer deleteWrapper(Consumer wrapper) { + return this.sqlTemp.delete(getMSID("deleteWrapper"), wrapper); + } + + public PageData selectPage(ParamPageDTO paramPageDTO, Consumer wrapper) { + PageHelper.startPage(paramPageDTO.getPageIndex(), paramPageDTO.getPageSize()); + Page result = (Page) this.sqlTemp.selectList(getMSID("selectWrapper"), wrapper); + return PageData.newobj(result); + } + + public List select() { + return this.select(this); + } + + @Override + public List select(Object whereObject) { + return this.sqlTemp.selectList(getMSID("select"), toMap(whereObject)); + } + + public PageData selectPage(ParamPageDTO paramPageDTO) { + PageHelper.startPage(paramPageDTO.getPageIndex(), paramPageDTO.getPageSize()); + return PageData.newobj((Page) (this.select(this))); + } + + @Override + public T selectOne(Object whereObject) { + return this.sqlTemp.selectOne(getMSID("selectOne"), toMap(whereObject)); + } + + public T selectOne() { + return this.selectOne(this); + } + + @Override + public Integer selectCount(Object whereObject) { + List result = this.sqlTemp.selectList(getMSID("selectCount"), toMap(whereObject)); + return result.get(0); + } + + public Integer selectCount() { + return this.selectCount(this); + } + + @Override + public List selectAll() { + return this.sqlTemp.selectList(getMSID("selectAll"), new LinkedHashMap<>()); + } + + @Override + public T selectByPrimaryKey(Object paramPrimaryKey) { + return this.selectOne(poUtil.getParamPrimaryKey(paramPrimaryKey)); + } + + public T selectByPrimaryKey() { + return this.selectByPrimaryKey(this); + } + + @Override + public int delete(Object whereObject) { + return this.sqlTemp.delete(getMSID("delete"), toMap(whereObject)); + } + + @Override + public int deleteByPrimaryKey(Object paramPrimaryKey) { + return this.delete(poUtil.getParamPrimaryKey(paramPrimaryKey)); + } + + public int deleteByPrimaryKey() { + return this.deleteByPrimaryKey(this); + } + + public int delete() { + return this.delete(this); + } + + @Override + public int insert(T entity) { + return this.sqlTemp.insert(getMSID("insert"), entity); + } + + public int insert() { + return this.insert((T) this); + } + + public int update(Object paramSet, Object paramWhere) { + UpdateParam param = new UpdateParam(toMap(paramSet), toMap(paramWhere)); + return this.update(param); + } + + @Override + public int updateByPrimaryKey(Object whereValue) { + return this.update(toMap(this, false), poUtil.getParamPrimaryKeyByValue(whereValue)); + //poUtil.getParamWriteNotNull(this) + } + + @Override + public int update(UpdateParam updateParam) { + return this.sqlTemp.update(getMSID("update"), updateParam); + } + + public int updateByPrimaryKey() { + return this.updateByPrimaryKey(poUtil.getValueByPrimaryKey(this)); + } + + public int updateByPrimaryKey(Object paramSet, Object whereValue) { + return this.update(paramSet, poUtil.getParamPrimaryKeyByValue(whereValue)); + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/BaseProviderSqlSource.java b/common/src/main/java/com/qmrz/mybatis/BaseProviderSqlSource.java new file mode 100644 index 0000000..94708ea --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/BaseProviderSqlSource.java @@ -0,0 +1,205 @@ +package com.qmrz.mybatis; + +import com.qmrz.mybatis.sql.sqlnode.SqlNodeWrapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.scripting.xmltags.SqlNode; + +@Slf4j +public class BaseProviderSqlSource { + public SqlNode selectWrapper(MappedStatement ms, Class classPO) { + MapperUtil.setResultType(ms, classPO); + return new SqlNodeWrapper(classPO, "selectWrapper"); + } + + public SqlNode selectOneWrapper(MappedStatement ms, Class classPO) { + MapperUtil.setResultType(ms, classPO); + return new SqlNodeWrapper(classPO, "selectOneWrapper"); + } + + public SqlNode updateWrapper(MappedStatement ms, Class classPO) { + return new SqlNodeWrapper(classPO, "updateWrapper"); + } + + public SqlNode deleteWrapper(MappedStatement ms, Class classPO) { + return new SqlNodeWrapper(classPO, "deleteWrapper"); + } + + /** + * 该方法仅仅用来初始化ProviderSqlSource + * + * @param record + * @return + */ + public String dynamicSQL(Object record) { + log.info("BaseProviderSqlSource dynamicSQL"); + return "dynamicSQL"; + } + + public SqlNode select(MappedStatement ms, Class classPO) { + MapperUtil.setResultType(ms, classPO); + return new SqlNodeWrapper(classPO, "select"); + + //修改返回值类型为实体类型 +// MapperUtil.setResultType(ms, classPO); +// +// SqlUtil sqlUtil = new SqlUtil(classPO); +// +// StringBuilder sql = new StringBuilder(); +// sql.append(sqlUtil.selectAllColumns()); +// sql.append(sqlUtil.fromTable()); +// sql.append(sqlUtil.whereAllIfFieldXML()); +// sql.append(sqlUtil.orderByDefault()); +// +// return sql.toString(); + } + + /** + * 查询全部结果 + */ + public SqlNode selectAll(MappedStatement ms, Class classPO) { + MapperUtil.setResultType(ms, classPO); + return new SqlNodeWrapper(classPO, "select"); + //修改返回值类型为实体类型 +// MapperUtil.setResultType(ms, classPO); +// +// SqlUtil sqlUtil = new SqlUtil(classPO); +// +// StringBuilder sql = new StringBuilder(); +// sql.append(sqlUtil.selectAllColumns()); +// sql.append(sqlUtil.fromTable()); +// sql.append(sqlUtil.orderByDefault()); +// +// return sql.toString(); + } + + public SqlNode selectOne(MappedStatement ms, Class classPO) { + MapperUtil.setResultType(ms, classPO); + return new SqlNodeWrapper(classPO, "selectOne"); + + //修改返回值类型为实体类型 +// MapperUtil.setResultType(ms, classPO); +// SqlUtil sqlUtil = new SqlUtil(classPO); +// +// StringBuilder sql = new StringBuilder(); +// sql.append(sqlUtil.selectAllColumns()); +// sql.append(sqlUtil.fromTable()); +// sql.append(sqlUtil.whereXML()); +// sql.append(sqlUtil.limit(1)); +// return sql.toString(); + } + + /** + * 根据主键字段进行查询,查询条件使用等号 + */ + public SqlNode selectByPrimaryKey(MappedStatement ms, Class classPO) { + MapperUtil.setResultType(ms, classPO); + return new SqlNodeWrapper(classPO, "select"); + + //修改返回值类型为实体类型 +// MapperUtil.setResultType(ms, classPO); +// +// SqlUtil sqlUtil = new SqlUtil(classPO); +// +// StringBuilder sql = new StringBuilder(); +// sql.append(sqlUtil.selectAllColumns()); +// sql.append(sqlUtil.fromTable()); +// sql.append(sqlUtil.whereByPrimaryKeyXML()); +// +// return sql.toString(); + } + + /** + * 根据实体中的属性查询总数,查询条件使用等号 + */ + public SqlNode selectCount(MappedStatement ms, Class classPO) { + MapperUtil.setResultType2(ms, Integer.class,"_count"); + return new SqlNodeWrapper(classPO, "selectCount"); + + + //修改返回值类型为实体类型 +// SqlUtil sqlUtil = new SqlUtil(classPO); +// +// StringBuilder sql = new StringBuilder(); +// sql.append(sqlUtil.selectCount()); +// sql.append(sqlUtil.fromTable()); +// sql.append(sqlUtil.whereAllIfFieldXML()); +// +// return sql.toString(); + } + + /** + * 根据主键字段进行删除,方法参数必须包含完整的主键属性 + */ + public SqlNode deleteByPrimaryKey(MappedStatement ms, Class classPO) { + return new SqlNodeWrapper(classPO, "delete"); + +// SqlUtil sqlUtil = new SqlUtil(classPO); +// StringBuilder sql = new StringBuilder(); +// sql.append(sqlUtil.deleteFrom()); +// sql.append(sqlUtil.whereByPrimaryKeyXML()); +// return sql.toString(); + } + + /** + * 根据实体属性作为条件进行删除,查询条件使用等号 + */ + public SqlNode delete(MappedStatement ms, Class classPO) { + return new SqlNodeWrapper(classPO, "delete"); + +// SqlUtil sqlUtil = new SqlUtil(classPO); +// StringBuilder sql = new StringBuilder(); +// sql.append(sqlUtil.deleteFrom()); +// sql.append(sqlUtil.whereAllIfFieldXML()); +// return sql.toString(); + } + + /** + * 保存一个实体,null的属性不会保存,会使用数据库默认值 + */ + public SqlNode insert(MappedStatement ms, Class classPO) { + return new SqlNodeWrapper(classPO, "insert"); + +// SqlUtil sqlUtil = new SqlUtil(classPO); +// StringBuilder sql = new StringBuilder(); +// sql.append(sqlUtil.insertXML()); +// return sql.toString(); + } + +// /** +// * 保存一个实体,所有字段都会插入,null的属性也会保存,不会使用数据库默认值 +// */ +// public String insertAllProperty(MappedStatement ms){ +// System.out.println("BaseProviderSqlSource select"); +// return "select id,name from test where 1=#{id}"; +// } + + /** + * 根据主键更新实体全部字段,null值不会被更新 + */ + public SqlNode updateByPrimaryKey(MappedStatement ms, Class classPO) { + return new SqlNodeWrapper(classPO, "update"); +// SqlUtil sqlUtil = new SqlUtil(classPO); +// StringBuilder sql = new StringBuilder(); +// sql.append(sqlUtil.updateSetXML()); +// sql.append(sqlUtil.whereByPrimaryKeyXML()); +// return sql.toString(); + } + + public SqlNode update(MappedStatement ms, Class classPO) { + return new SqlNodeWrapper(classPO, "update"); +// SqlUtil sqlUtil = new SqlUtil(classPO); +// StringBuilder sql = new StringBuilder(); +// sql.append(sqlUtil.updateSetXML()); +// sql.append(sqlUtil.whereByPrimaryKeyXML()); +// return sql.toString(); + } + + /** + * 根据主键更新实体全部字段,null值也会被更新 + */ +// public String updateByPrimaryKeyAllProperty(MappedStatement ms){ +// System.out.println("BaseProviderSqlSource select"); +// return "select id,name from test where 1=#{id}"; +// } +} diff --git a/common/src/main/java/com/qmrz/mybatis/DBWrapper.java b/common/src/main/java/com/qmrz/mybatis/DBWrapper.java new file mode 100644 index 0000000..d3a09f5 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/DBWrapper.java @@ -0,0 +1,5 @@ +package com.qmrz.mybatis; + +public class DBWrapper { + +} diff --git a/common/src/main/java/com/qmrz/mybatis/INull.java b/common/src/main/java/com/qmrz/mybatis/INull.java new file mode 100644 index 0000000..fc1c3bf --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/INull.java @@ -0,0 +1,4 @@ +package com.qmrz.mybatis; + +public interface INull { +} diff --git a/common/src/main/java/com/qmrz/mybatis/Mapper.java b/common/src/main/java/com/qmrz/mybatis/Mapper.java new file mode 100644 index 0000000..9f89bf5 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/Mapper.java @@ -0,0 +1,131 @@ +package com.qmrz.mybatis; + +import com.qmrz.mybatis.sql.BaseWrapper; +import org.apache.ibatis.annotations.*; + +import java.util.List; +import java.util.function.Consumer; + +public interface Mapper { +// @Options(useGeneratedKeys = true, keyProperty = "id") + @SelectProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") + List selectWrapper(Consumer wrapper); + + @SelectProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") + T selectOneWrapper(Consumer wrapper); + + @UpdateProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") + Integer updateWrapper(Object param, Consumer wrapper); + + @DeleteProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") + Integer deleteWrapper(Consumer wrapper); + + /** + * 根据实体中的属性值进行查询,查询条件使用等号 + * + * @param whereObject map或实体 + * @return + */ + @SelectProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") + List select(Object whereObject); + + //@SelectProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") + //List selectList(T entity, IWrapper wrapper); + + /** + * 根据实体中的属性进行查询,只能有一个返回值,有多个结果取第1个 + * + * @param whereObject map或实体 + * @return + */ + @SelectProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") + T selectOne(Object whereObject); + + /** + * 根据实体中的属性查询总数,查询条件使用等号 + * + * @param whereObject map或实体 + * @return + */ + @SelectProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") + Integer selectCount(Object whereObject); + + /** + * 查询全部结果 + * + * @return + */ + @SelectProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") + List selectAll(); + + /** + * 根据主键字段进行查询,查询条件使用等号 + * + * @param paramPrimaryKey map或实体 + * @return + */ + @SelectProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") + T selectByPrimaryKey(Object paramPrimaryKey); + + /** + * 根据主键字段进行删除,方法参数必须包含完整的主键属性 + * + * @param paramPrimaryKey map或实体 + * @return + */ + @DeleteProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") + int deleteByPrimaryKey(Object paramPrimaryKey); + + /** + * 根据实体属性作为条件进行删除,查询条件使用等号 + * + * @param whereObject map或实体 + * @return + */ + @DeleteProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") + int delete(Object whereObject); + + + /** + * 保存一个实体,null的属性不会保存,会使用数据库默认值 + * + * @param entity map或实体 + * @return + */ + @Options(useGeneratedKeys=true,keyProperty = "id") + @InsertProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") + int insert(T entity); + + /** + * 保存一个实体,所有字段都会插入,null的属性也会保存,不会使用数据库默认值 + * + * @param entity + * @return + */ +// @InsertProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") +// int insertAllProperty(T entity); + + /** + * 根据主键更新实体全部字段,null值不会被更新 + * + * @param paramMap map或实体 + * @return + */ + @UpdateProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") + int updateByPrimaryKey(Object paramMap); + + + @UpdateProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") + int update(Object paramMap); + + /** + * 根据主键更新实体全部字段,null值也会被更新 + * + * @param entity + * @return + */ +// @UpdateProvider(type = BaseProviderSqlSource.class, method = "dynamicSQL") +// int updateByPrimaryKeyAllProperty(T entity); + + +} diff --git a/common/src/main/java/com/qmrz/mybatis/MapperScan.java b/common/src/main/java/com/qmrz/mybatis/MapperScan.java new file mode 100644 index 0000000..a3547ca --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/MapperScan.java @@ -0,0 +1,234 @@ +package com.qmrz.mybatis; + +import com.qmrz.exception.ABException; +import com.qmrz.mybatis.service.BaseService; +import com.qmrz.utils.SpringContextUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.builder.annotation.ProviderSqlSource; +import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator; +import org.apache.ibatis.executor.keygen.NoKeyGenerator; +import org.apache.ibatis.mapping.*; +import org.apache.ibatis.reflection.MetaObject; +import org.apache.ibatis.reflection.SystemMetaObject; +import org.apache.ibatis.scripting.xmltags.DynamicSqlSource; +import org.apache.ibatis.scripting.xmltags.SqlNode; +import org.apache.ibatis.scripting.xmltags.TextSqlNode; +import org.apache.ibatis.session.Configuration; +import org.apache.ibatis.session.SqlSessionFactory; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; + +/** + * mybatis功能扩展,实现无xml mapper + */ +@Slf4j +public class MapperScan { + /** + * 通用方法 + */ + private Map methods; + private Configuration configuration; + private BaseProviderSqlSource baseProviderSqlSource; + + public MapperScan() { + load(SpringContextUtil.getBean(SqlSessionFactory.class)); + } + + public MapperScan(SqlSessionFactory sqlSessionFactory) { + load(sqlSessionFactory); + } + + public void load(SqlSessionFactory sqlSessionFactory) { + this.methods = new HashMap<>(); + this.baseProviderSqlSource = new BaseProviderSqlSource(); + this.configuration = sqlSessionFactory.getConfiguration(); + + for (Method method : BaseProviderSqlSource.class.getDeclaredMethods()) { + methods.put(method.getName(), method); + } + } + + /** + * 同时扩展mybatis接口和实体功能 + * @throws IllegalAccessException + * @throws InvocationTargetException + * @throws ClassNotFoundException + */ + public void register() throws IllegalAccessException, InvocationTargetException, ClassNotFoundException { + log.info("扩展 mybatis 接口、实体"); + registerMapper(); + registerActiveRecord(); + } + + /** + * 实现无xml的mapper接口 + * @throws InvocationTargetException + * @throws IllegalAccessException + */ + public void registerMapper() throws InvocationTargetException, IllegalAccessException { +// log.info("MapperScan registerMapper"); + for (Object object : new ArrayList(configuration.getMappedStatements())) { + if (!(object instanceof MappedStatement)) { + continue; + } + + MappedStatement mappedStatement = (MappedStatement) object; + SqlSource sqlSourceTemp = mappedStatement.getSqlSource(); + if (!(sqlSourceTemp instanceof ProviderSqlSource)) { + continue; + } + + log.info("mappedStatement:" + mappedStatement.getId()); + + String msId = mappedStatement.getId(); + Method method = methods.get(msId.substring(msId.lastIndexOf(".") + 1)); + if (method == null) { + log.warn("通用mapper:" + msId + " 在BaseProviderSqlSource找不到提供方法"); + continue; + } + + Class classPO = MapperUtil.getMapperClass(mappedStatement); + SqlSource sqlSource = createSqlSource(method, mappedStatement, classPO, null); + MetaObject msObject = SystemMetaObject.forObject(object); + msObject.setValue("sqlSource", sqlSource); + } + } + + /** + * 创建字符串类型sqlSource + * @param script + * @param parameterType + * @return + */ + private SqlSource createSqlSource(String script, Class parameterType) { + StringBuilder sql = new StringBuilder(); + sql.append(""); + return configuration.getDefaultScriptingLanguageInstance() + .createSqlSource(configuration, sql.toString(), parameterType); + } + + /** + * 创建sqlSource对象,自动识别sql类型(String、SqlNode) + * @param method + * @param mappedStatement + * @param classPO + * @param parameterType + * @return + * @throws InvocationTargetException + * @throws IllegalAccessException + */ + private SqlSource createSqlSource(Method method, MappedStatement mappedStatement, Class classPO, Class parameterType) throws InvocationTargetException, IllegalAccessException { + SqlSource sqlSource; + if (String.class.equals(method.getReturnType())) { + String script = (String) method.invoke(baseProviderSqlSource, mappedStatement, classPO); + sqlSource = createSqlSource(script, parameterType); + } else if (SqlNode.class.isAssignableFrom(method.getReturnType())) { + SqlNode sqlNode = (SqlNode) method.invoke(baseProviderSqlSource, mappedStatement, classPO); + sqlSource = new DynamicSqlSource(configuration, sqlNode); + } else { + throw new ABException("未知sql源"); + } + return sqlSource; + } + + /** + * 扩展实体功能 + * @throws ClassNotFoundException + * @throws InvocationTargetException + * @throws IllegalAccessException + */ + public void registerActiveRecord() throws ClassNotFoundException, InvocationTargetException, IllegalAccessException { + //获取实体资源 + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + Resource[] r = new Resource[0]; + try { + r = resolver.getResources("classpath*:com/qmrz/domain/**/*.class"); + } catch (IOException e) { + e.printStackTrace(); + } + + //实体资源转字符串 + List classList = new ArrayList<>(); + try { + for (Resource resource : r) { + String path = resource.getURL().getPath(); + path = path.replace("\\", "/"); + classList.add(path.substring(path.indexOf("/com/") + 1 + , path.lastIndexOf(".class")) + .replace("/", ".")); + } + } catch (IOException e) { + e.printStackTrace(); + } + + //将属于BasePO类的实体进行扩展 + for (String str : classList) { + Class classPO = Class.forName(str); + if (!BasePO.class.isAssignableFrom(classPO)) { + continue; + } + Method[] methods = BaseService.class.getMethods(); + for (Method method : methods) { + registerActiveRecordMethod(method.getName(), classPO); + } + } + } + + /** + * 注册实体扩展方法 + * @param methodName + * @param classPO + * @throws InvocationTargetException + * @throws IllegalAccessException + */ + private void registerActiveRecordMethod(String methodName, Class classPO) throws InvocationTargetException, IllegalAccessException { + String id = classPO.getName() + "_" + methodName; + String newMsId = id + "_ActiveRecord"; + + //创建默认动态sql + SqlSource sqlSource = new DynamicSqlSource(configuration, new TextSqlNode("SQL_CommonMapper")); + SqlCommandType sqlCommandType = null; + + if (methodName.startsWith("select")) { + sqlCommandType = SqlCommandType.SELECT; + } else if (methodName.startsWith("update")) { + sqlCommandType = SqlCommandType.UPDATE; + } else if (methodName.startsWith("insert")) { + sqlCommandType = SqlCommandType.INSERT; + } else if (methodName.startsWith("delete")) { + sqlCommandType = SqlCommandType.DELETE; + } + + //Statement构建配置 + MappedStatement.Builder builder = + new MappedStatement.Builder(configuration + , newMsId, sqlSource, sqlCommandType); + if (methodName.startsWith("insert")) { + builder.keyProperty("id"); + } + + //Statement构建 + MappedStatement statement = builder.build(); + //insert后支持主键注入 + builder.keyGenerator(SqlCommandType.INSERT.equals(sqlCommandType) ? new Jdbc3KeyGenerator() : new NoKeyGenerator()); + + //获取statement对应方法 + Method method = methods.get(methodName); + //扩展方法与statement绑定并返回SqlSource + sqlSource = createSqlSource(method, statement, classPO, null); + + //配置statement方法的sql源 + MetaObject msObject = SystemMetaObject.forObject(statement); + msObject.setValue("sqlSource", sqlSource); + + //注入mybatis + configuration.addMappedStatement(statement); + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/MapperScannerConfigurer.java b/common/src/main/java/com/qmrz/mybatis/MapperScannerConfigurer.java new file mode 100644 index 0000000..f07f21b --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/MapperScannerConfigurer.java @@ -0,0 +1,33 @@ +package com.qmrz.mybatis; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; + +@Slf4j +public class MapperScannerConfigurer extends org.mybatis.spring.mapper.MapperScannerConfigurer { + public void setMarkerInterface(Class superClass) { + log.info("setMarkerInterface"); + log.info(superClass.getName()); + super.setMarkerInterface(superClass); +// this.markerInterface = superClass; +// if (Marker.class.isAssignableFrom(superClass)) { +// mapperHelper.registerMapper(superClass); +// } + } + @Override + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { + log.info("postProcessBeanDefinitionRegistry"); + + super.postProcessBeanDefinitionRegistry(registry); + + + } + + @Override + public void afterPropertiesSet() throws Exception { + log.info("afterPropertiesSet"); + + super.afterPropertiesSet(); + + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/MapperUtil.java b/common/src/main/java/com/qmrz/mybatis/MapperUtil.java new file mode 100644 index 0000000..3e49209 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/MapperUtil.java @@ -0,0 +1,96 @@ +package com.qmrz.mybatis; + +import com.qmrz.exception.ABException; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.ResultMap; +import org.apache.ibatis.mapping.ResultMapping; +import org.apache.ibatis.reflection.MetaObject; +import org.apache.ibatis.reflection.SystemMetaObject; +import org.apache.ibatis.session.Configuration; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Slf4j +public class MapperUtil { + /** + * 获取Mapper的泛型实体 + * + * @param ms + * @return + */ + public static Class getMapperClass(MappedStatement ms) { +// log.warn(ms.getResource()); + String poClassName = ms.getResource().replace(".java (best guess)", "") + .replace("/", "."); + + //获取实体 + Class classPO; + try { + Class clazz = Class.forName(poClassName); + classPO = (Class) ((ParameterizedType) (clazz.getGenericInterfaces()[0])).getActualTypeArguments()[0]; + + } catch (Exception e) { + e.printStackTrace(); + throw new ABException("通用Mapper:" + e.getMessage()); + } + +// log.warn(classPO.getName()); + return classPO; + } + + public static void setResultType(MappedStatement ms, Class classPO) { + Configuration configuration = ms.getConfiguration(); + MetaObject msObject = SystemMetaObject.forObject(ms); + +// List resultMappings = new ArrayList<>(); +// MetaObject msObject = SystemMetaObject.forObject(ms); +// ResultMap.Builder builder = new ResultMap.Builder(ms.getConfiguration() +// , classPO.getName() + "_ResultType", +// classPO, resultMappings, true); +// +// +// +// List resultMaps = new ArrayList<>(); +// resultMaps.add(builder.build()); +// msObject.setValue("resultMaps", Collections.unmodifiableList(resultMaps)); + + List resultMappings = new ArrayList<>(); + + for (Field field : classPO.getDeclaredFields()) { + ResultMapping.Builder builder = new ResultMapping.Builder(configuration + , field.getName(), field.getName()//, POUtil.getFieldNameByDB(field) + , field.getType()); + resultMappings.add(builder.build()); + } + + ResultMap.Builder builder = new ResultMap.Builder(configuration, classPO.getName() + "_CommonMapperResultMap", + classPO, resultMappings, true); + + List resultMaps = new ArrayList<>(); + resultMaps.add(builder.build()); + msObject.setValue("resultMaps", Collections.unmodifiableList(resultMaps)); + } + + public static void setResultType2(MappedStatement ms, Class cla, String fieldName) { + Configuration configuration = ms.getConfiguration(); + MetaObject msObject = SystemMetaObject.forObject(ms); + List resultMappings = new ArrayList<>(); + + ResultMapping.Builder builder2 = new ResultMapping.Builder(configuration + , fieldName, fieldName//, POUtil.getFieldNameByDB(field) + , cla); + resultMappings.add(builder2.build()); + + ResultMap.Builder builder = new ResultMap.Builder(configuration, cla.getName() + "_CommonMapperResultMap", + cla, resultMappings, true); + + List resultMaps = new ArrayList<>(); + resultMaps.add(builder.build()); + msObject.setValue("resultMaps", Collections.unmodifiableList(resultMaps)); + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/PO.java b/common/src/main/java/com/qmrz/mybatis/PO.java new file mode 100644 index 0000000..07df739 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/PO.java @@ -0,0 +1,25 @@ +package com.qmrz.mybatis; + +import lombok.Data; +import org.apache.commons.lang.StringUtils; + +import java.util.List; + +/** + * 实体属性与DB字段 + */ +@Data +public class PO { + private String tableNameByDB; + private List fieldList; + private Class entityClass; + private String schemasName; + + public String getTableNameByDBAll() { + if (StringUtils.isEmpty(this.schemasName)) { + return this.tableNameByDB; + } else { + return this.schemasName + "." + this.tableNameByDB; + } + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/POPropertie.java b/common/src/main/java/com/qmrz/mybatis/POPropertie.java new file mode 100644 index 0000000..d3da044 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/POPropertie.java @@ -0,0 +1,28 @@ +package com.qmrz.mybatis; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.lang.reflect.Field; + +/** + * 实体属性与DB字段 + */ +@Data +@AllArgsConstructor +public class POPropertie { + private String fieldName; + private String fieldNameByDB; + private Field field; + private Class javaType; + /** + * 默认为null,若不为null,则对应db类型字段串 + */ + private String dbType; + /** + * 0:无排序 1:asc 2:desc + */ + private int orderByStatus; + private int orderByIndex; + private boolean isPrimarykey; +} diff --git a/common/src/main/java/com/qmrz/mybatis/POPropertieValue.java b/common/src/main/java/com/qmrz/mybatis/POPropertieValue.java new file mode 100644 index 0000000..f783567 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/POPropertieValue.java @@ -0,0 +1,18 @@ +package com.qmrz.mybatis; + +import lombok.Data; + +/** + * 实体属性与DB字段 + */ +@Data +public class POPropertieValue extends POPropertie { + + private Object value; + + public POPropertieValue(POPropertie p, Object value) { + super(p.getFieldName(), p.getFieldNameByDB(), p.getField(), p.getJavaType(),p.getDbType() + , p.getOrderByStatus(), p.getOrderByIndex(), p.isPrimarykey()); + this.value = value; + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/POProxy.java b/common/src/main/java/com/qmrz/mybatis/POProxy.java new file mode 100644 index 0000000..e660b1a --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/POProxy.java @@ -0,0 +1,61 @@ +package com.qmrz.mybatis; + +import org.springframework.cglib.proxy.Enhancer; +import org.springframework.cglib.proxy.MethodInterceptor; +import org.springframework.cglib.proxy.MethodProxy; + +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.util.*; + +/** + * 实体代理类,用于监控实体属性的变化 + */ +public class POProxy implements MethodInterceptor { + private Enhancer enhancer = new Enhancer(); + + private Class classPO; + private Map setList = new LinkedHashMap<>(); + + public Class getClassPO() { + return classPO; + } + + public Map getSetList() { + return setList; + } + + /** + * 创建代理 + * @param classPO + * @param + * @return + */ + public T getProxy(Class classPO) { + this.classPO = classPO; + //设置创建子类的类 + enhancer.setSuperclass(classPO); + enhancer.setCallback(this); + return (T) enhancer.create(); + } + + /** + * 监控set属性 + * @param o + * @param method + * @param objects + * @param methodProxy + * @return + * @throws Throwable + */ + @Override + public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { + String methodName = method.getName().toLowerCase(); + if (methodName.startsWith("set")) { + setList.put(methodName.substring(3, methodName.length()), objects[0]); + } + + //代理类调用父类的方法 + return methodProxy.invokeSuper(o, objects); + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/POUtil.java b/common/src/main/java/com/qmrz/mybatis/POUtil.java new file mode 100644 index 0000000..6ae017c --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/POUtil.java @@ -0,0 +1,463 @@ +package com.qmrz.mybatis; + +import com.qmrz.exception.ABException; +import com.qmrz.mybatis.annotation.*; +import org.apache.ibatis.reflection.MetaObject; +import org.apache.ibatis.reflection.SystemMetaObject; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.*; + +public class POUtil { + private static final Class AnnotationID = ID.class; + private static final Class AnnotationDBType = DBType.class; + private static final Class AnnotationFieldName = FieldName.class; + private static final Class AnnotationTableName = TableName.class; + private static final Class AnnotationOrderByDefault = OrderByDefault.class; + + private Class classPO; + private String tableNameByDB; + private String schemasNameByDB; + private List propertieList; + private List propertieListOrderBy; + private POPropertie primarykey; + + public POUtil(Class classPO) { + this.classPO = classPO; + this.loadTableNameByDB(); + this.loadSchemasNameByDB(); + this.loadPropertieList(); + this.loadOrderBy(); + } + + public String getTableNameByDB() { + return tableNameByDB; + } + + public String getSchemasNameByDB() { + return schemasNameByDB; + } + + public List getPropertieList() { + return propertieList; + } + + public List getPropertieListOrderBy() { + return propertieListOrderBy; + } + + public POPropertie getPrimarykey() { + return primarykey; + } + + private void loadOrderBy() { + this.propertieListOrderBy = new ArrayList<>(); + this.propertieList.forEach(item -> { + if (item.getOrderByStatus() != 0) { + this.propertieListOrderBy.add(item); + } + }); + + Collections.sort(this.propertieListOrderBy, new Comparator() { + @Override + public int compare(POPropertie o1, POPropertie o2) { + if (o1.getOrderByIndex() < o2.getOrderByIndex()) { + return -1; + } else if (o1.getOrderByIndex() == o2.getOrderByIndex()) { + return 0; + } else { + return 1; + } + } + }); + } + + /** + * 写入参数,insert和update时的参数,不包含主键 和 为null + * + * @param po + * @return + */ +// public Map getParamWriteNotNull(Object po) { +// Map param = new LinkedHashMap<>(); +// getPropertieNotNull(po).forEach(item -> { +// param.put(item.getFieldName(), item.getValue()); +// }); +// return param; +// } + + /** + * 实体转map,若实体对象在当前实体结构中不存在,则不加入map + * + * @param po + * @return + */ + public Map getParam(Object po) { + Map param = new LinkedHashMap<>(); + MetaObject mo = SystemMetaObject.forObject(po); + List names = Arrays.asList(mo.getGetterNames()); + + getPropertieList().forEach(item -> { + String dbname = item.getFieldNameByDB(); + if (names.contains(dbname)) { + param.put(dbname, mo.getValue(dbname)); + } + }); + return param; + } + + /** + * @param paramPrimaryKey 实体(里面存储key字段) + * @return + */ + public Map getParamPrimaryKey(Object paramPrimaryKey) { + MetaObject msObject = SystemMetaObject.forObject(paramPrimaryKey); + Map param = new LinkedHashMap<>(); + param.put(this.primarykey.getFieldNameByDB() + , msObject.getValue(this.primarykey.getFieldName())); + return param; + } + + public Map getParamPrimaryKeyByValue(Object value) { + Map param = new LinkedHashMap<>(); + param.put(this.primarykey.getFieldNameByDB() + , value); + return param; + } + + public Object getValueByPrimaryKey(Object objectPO) { + MetaObject msObject = SystemMetaObject.forObject(objectPO); + return msObject.getValue(this.primarykey.getFieldName()); + } + +// /** +// * 写入参数,insert和update时的参数,不包含主键 和 为null +// * +// * @return +// */ +// public Map getParamWriteNotNull(Object po) { +// MetaObject msObject = SystemMetaObject.forObject(po); +// Map param = new LinkedHashMap<>(); +// +// for (POPropertie item : this.getPropertieList()) { +// if (item.isPrimarykey()) { +// continue; +// } +// +// Object val = msObject.getValue(item.getFieldName()); +// if (val == null) { +// continue; +// } +// +// param.put(item.getFieldName(), val); +// } +// return param; +// } + + /** + * 获取所有非null属性(不含主键、含属性值) + * + * @param po + * @return + */ +// public List getPropertieNotNull(Object po) { +// List fieldList = new ArrayList<>(); +// MetaObject msObject = SystemMetaObject.forObject(po); +// +// for (POPropertie propertie : this.propertieList) { +// if (propertie.isPrimarykey()) { +// continue; +// } +// Object fieldValue = msObject.getValue(propertie.getFieldName()); +// if (fieldValue == null) { +// continue; +// } +// fieldList.add(new POPropertieValue(propertie, fieldValue)); +// } +// return fieldList; +// } + + /** + * Object转map + * + * @param po + * @return + */ + public static Map getMap(Object po) { + List fieldList = new ArrayList<>(); + MetaObject msObject = SystemMetaObject.forObject(po); + Field[] fields = po.getClass().getDeclaredFields(); + Map result = new LinkedHashMap<>(); + for (Field field : fields) { + result.put(field.getName(), msObject.getValue(field.getName())); + } + + return result; + } + +// public Map getMapNotNull(Object po) { +// List fieldList = new ArrayList<>(); +// MetaObject msObject = SystemMetaObject.forObject(po); +// +// Map result = new LinkedHashMap<>(); +// for (POPropertie item : this.propertieList) { +// Object val = msObject.getValue(item.getFieldName()); +// if (val == null) { +// continue; +// } +// if (item.isPrimarykey()) { +// continue; +// } +// result.put(item.getFieldName(), val); +// } +// +// return result; +// } + + /** + * 填充实体数据,将object 属性填充到 objectProxy + * + * @param objectProxy + * @param object + */ + public static void fillNotNull(BasePO objectProxy, Object object, boolean isAllowNull) { + List fieldList = new ArrayList<>(); + MetaObject msObjectProxy = SystemMetaObject.forObject(objectProxy); + MetaObject msObject = SystemMetaObject.forObject(object); + + for (Field field : objectProxy._getProxy().getClassPO().getDeclaredFields()) { + if (!msObject.hasGetter(field.getName())) { + continue; + } + + Object obj = msObject.getValue(field.getName()); + if (obj == null) { + if (isAllowNull) { + continue; + } else { + //若object有属性,则必须不能为null + throw new ABException(field.getName() + "不允许为空"); + } + } + msObjectProxy.setValue(field.getName(), obj); + } + } + + public static void fillNotNull(BasePO objectProxy, Object object, String[] fieldNameList, boolean isAllowNull) { + List fieldList = new ArrayList<>(); + MetaObject msObjectProxy = SystemMetaObject.forObject(objectProxy); + MetaObject msObject = SystemMetaObject.forObject(object); + + for (String fieldName : fieldNameList) { + if (!msObject.hasGetter(fieldName)) { + continue; + } + + Object obj = msObject.getValue(fieldName); + if (obj == null) { + if (isAllowNull) { + continue; + } else { + //若object有属性,则必须不能为null + throw new ABException(fieldName + "不允许为空"); + } + } + msObjectProxy.setValue(fieldName, obj); + } + } + + /** + * 只返回指定参数 + * + * @param po + * @param names + * @return + */ + public static Map getMapByNames(Object po, String... names) { + Map result = new LinkedHashMap<>(); + if (po == null) { + return result; + } + MetaObject msObject = SystemMetaObject.forObject(po); + for (String name : names) { + result.put(name, msObject.getValue(name)); + } + return result; + } + + /** + * 只返回指定参数 + * + * @param list + * @param names + * @return + */ + public static List> getListMapByNames(List list, String... names) { + List> result = new ArrayList<>(); + for (Object o : list) { + result.add(getMapByNames(o, names)); + } + return result; + } + + /** + * 获取所有属性(不含值) + * + * @return + */ + public void loadPropertieList() { + this.propertieList = new ArrayList<>(); + Field[] fields = classPO.getDeclaredFields(); +// POPropertie propID = null; + POPropertie propIDTmp = null; + boolean hasOrderBy = false;//是否有指定排序注解,若没有默认主键降序排序 + for (Field field : fields) { + String fieldName = field.getName(); + String fieldNameByDB = getFieldNameByDB(field); + + //获取order by + int orderByStatus = 0; + int orderByIndex = 0; + if (field.isAnnotationPresent(AnnotationOrderByDefault)) { + OrderByDefault orderByDefault + = ((OrderByDefault) field.getAnnotation(AnnotationOrderByDefault)); + boolean isasc = orderByDefault.isasc(); + if (isasc) { + orderByStatus = 1; + } else { + orderByStatus = 2; + } + orderByIndex = orderByDefault.index(); + hasOrderBy = true; + } + + //验证是否主键 + boolean isPrimarykey = false; + if (field.isAnnotationPresent(AnnotationID)) { + if (this.primarykey != null) { + throw new ABException("发现有多个 @ID 注释"); + } + isPrimarykey = true; + } + + String dbType = null; + if (field.isAnnotationPresent(AnnotationDBType)) { + dbType = ((DBType) field.getAnnotation(AnnotationDBType)).type(); + } + + POPropertie p = new POPropertie(fieldName, fieldNameByDB, field, field.getType(), dbType + , orderByStatus, orderByIndex, isPrimarykey); + + if (isPrimarykey) { + this.primarykey = p; + } + + if ("id".equals(fieldName)) { + p.setPrimarykey(true); + propIDTmp = p; + } + + this.propertieList.add(p); + } + + if (this.primarykey == null) { + if (propIDTmp == null) { + if (tableNameByDB.length() >= 4 && "view".equals(tableNameByDB.substring(tableNameByDB.length() - 4))) { + this.primarykey = new POPropertie(null, null, null, null, null, 1, 1, false); + } else { + throw new ABException("必须指定主键:" + this.classPO.getName()); + } + }else{ + this.primarykey = propIDTmp; + } + } + + //若没有指定排序,则按主键降序排序 + if (!hasOrderBy) { + this.primarykey.setOrderByStatus(2); + this.primarykey.setOrderByIndex(0); + } + } + + public POPropertie getPropertieByName(String name) { + for (POPropertie item : this.propertieList) { + if (name.equals(item.getFieldName())) { + return item; + } + } + throw new ABException("找不到字段:" + this.classPO.getName() + ":" + name); + } + + /** + * 获取数据库字段名 + * + * @param field + * @return + */ + public static String getFieldNameByDB(Field field) { + String fieldNameByDB; + if (field.isAnnotationPresent(AnnotationFieldName)) { + fieldNameByDB = ((FieldName) field.getAnnotation(AnnotationFieldName)).name(); + } else { + fieldNameByDB = field.getName(); + } + return fieldNameByDB; + } + +// private static boolean getFieldOrderyByDefault(Field field) { +// if (!field.isAnnotationPresent(AnnotationOrderByDefault)) { +// return false; +// } +// +// boolean isasc = ((OrderByDefault) field.getAnnotation(AnnotationOrderByDefault)).isasc(); +// return getFieldNameByDB(field) + (isasc ? " asc" : " desc"); +// } + + /** + * 获取数据库表名 + * + * @return + */ + private void loadTableNameByDB() { + if (classPO.isAnnotationPresent(AnnotationTableName)) { + this.tableNameByDB = ((TableName) classPO.getAnnotation(AnnotationTableName)).name(); + return; + } + + String tableName = classPO.getSimpleName().toLowerCase(); + if (tableName.lastIndexOf("po") > 0) { + tableName = tableName.substring(0, tableName.length() - 2); + } + + this.tableNameByDB = tableName; + } + + private void loadSchemasNameByDB() { + if (classPO.isAnnotationPresent(AnnotationTableName)) { + this.schemasNameByDB = ((TableName) classPO.getAnnotation(AnnotationTableName)).schemasName(); + return; + } + this.schemasNameByDB = ""; + } + +// /** +// * 是否有该注解 +// * +// * @param annotationClass +// * @return +// */ +// public boolean isAnnotationPresent(Class annotationClass) { +// boolean result = false; +// if (field != null) { +// result = field.isAnnotationPresent(annotationClass); +// } +// if (!result && setter != null) { +// result = setter.isAnnotationPresent(annotationClass); +// } +// if (!result && getter != null) { +// result = getter.isAnnotationPresent(annotationClass); +// } +// return result; +// } +} diff --git a/common/src/main/java/com/qmrz/mybatis/SqlUtil.java b/common/src/main/java/com/qmrz/mybatis/SqlUtil.java new file mode 100644 index 0000000..2a22131 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/SqlUtil.java @@ -0,0 +1,344 @@ +package com.qmrz.mybatis; + + +import com.qmrz.exception.ABException; +import org.apache.commons.lang.StringUtils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class SqlUtil { + + private PO po; + private POUtil poUtil; + + public SqlUtil(Class entityClass) { + + po = new PO(); + poUtil = new POUtil(entityClass); + + po.setEntityClass(entityClass); + po.setFieldList(poUtil.getPropertieList()); + po.setTableNameByDB(poUtil.getTableNameByDB()); + po.setSchemasName(poUtil.getSchemasNameByDB()); + + if (po.getFieldList().size() == 0) { + throw new ABException("没有字段"); + } + } + + public StringBuilder selectAllColumns() { + StringBuilder sql = new StringBuilder(); + List list = new ArrayList<>(); + sql.append("select "); + + po.getFieldList().forEach( + item -> list.add(fieldDBSelect(item)) + ); + sql.append(StringUtils.join(list.toArray(), ",")); + return sql; + } + + public StringBuilder selectCount(String fieldName) { + StringBuilder sql = new StringBuilder(); + sql.append("select count(").append(fieldName).append(") as _count"); + return sql; + } + + public StringBuilder selectCount() { + return selectCount(poUtil.getPrimarykey().getFieldNameByDB()); + } + +// private String getAllFieldStr() { +// List properties = po.getFieldList(); +// StringBuilder sql = new StringBuilder(); +// properties.forEach( +// item -> sql.append(item.getFieldNameByDB()).append(",") +// ); +// +// return sql.substring(0, sql.length() - 1); +// } + + private String getOrderByStr() { + StringBuilder sql = new StringBuilder(); + + poUtil.getPropertieListOrderBy().forEach(item -> { + int orderByStatus = item.getOrderByStatus(); + String str = ""; + if (orderByStatus == 1) { + str = " asc"; + } else if (orderByStatus == 2) { + str = " desc"; + } + if (str.length() > 0) { + sql.append(item.getFieldNameByDB()).append(str).append(","); + } + }); + + if (sql.length() > 0) { + return sql.substring(0, sql.length() - 1); + //return " order by " + str; + } + + return ""; + } + + public StringBuilder fromTable() { + StringBuilder sql = new StringBuilder(); + sql.append(" from "); + sql.append(po.getTableNameByDBAll()); + return sql; + } + + public String whereByPrimaryKeyXML() { + StringBuilder sql = new StringBuilder(); + sql.append(" "); + + List properties = po.getFieldList(); + + sql.append(poUtil.getPrimarykey().getFieldNameByDB() + + "=#{" + poUtil.getPrimarykey().getFieldName() + "}"); + + sql.append(""); + return sql.toString(); + } + + public String whereByPrimaryKey() { + StringBuilder sql = new StringBuilder(); + + List properties = po.getFieldList(); + sql.append(" where "); + sql.append(poUtil.getPrimarykey().getFieldNameByDB() + + "=#{" + poUtil.getPrimarykey().getFieldName() + "}"); + + return sql.toString(); + } + + public String whereNotNullXML() { + StringBuilder sql = new StringBuilder(); + sql.append(" "); + + List properties = po.getFieldList(); + + for (POPropertie column : properties) { + sql.append(ifNotNullXML(column, column.getFieldNameByDB() + "=#{" + column.getFieldName() + "}")); + } + + sql.append(""); + return sql.toString(); + } + + public String whereXML() { + StringBuilder sql = new StringBuilder(); + sql.append(" "); + + List properties = po.getFieldList(); + + for (POPropertie column : properties) { + sql.append(" and " + column.getFieldNameByDB() + "=#{" + column.getFieldName() + "}"); + } + + sql.append(""); + return sql.toString(); + } + +// public String where() { +// StringBuilder sql = new StringBuilder(); +// sql.append(" where "); +// List properties = po.getFieldList(); +// +// List list = new ArrayList<>(); +// for (POPropertie column : properties) { +// list.add(column.getFieldNameByDB() + "=#{" + column.getFieldName() + "}"); +// } +// sql.append(StringUtils.join(list.toArray()," and ")); +// return sql.toString(); +// } + + public StringBuilder whereByParam(Collection param) { + StringBuilder sql = new StringBuilder(); + if (param.size() > 0) { + sql.append(" where "); + } + + List list = new ArrayList<>(); + for (String column : param) { + POPropertie info = poUtil.getPropertieByName(column); + list.add(info.getFieldNameByDB() + "=#{" + column + "}"); + } + sql.append(StringUtils.join(list.toArray(), " and ")); + return sql; + } + + /** + * 不支持查询字符串为空的数据,若要查询,请使用wrapper + * + * @param column + * @param contents + * @return + */ + private String ifNotNullXML(POPropertie column, String contents) { + StringBuilder sql = new StringBuilder(); + sql.append(" "); + sql.append(contents); + sql.append(""); + return sql.toString(); + } + + public StringBuilder orderByDefault() { + StringBuilder sql = new StringBuilder(); + String orderBy = getOrderByStr(); + if (orderBy.length() == 0) { + return sql; + } + + sql.append(" order by "); + sql.append(orderBy); + return sql; + } + + public String updateSetNotNullXML() { + StringBuilder sql = new StringBuilder(); + sql.append("update ").append(po.getTableNameByDB()).append(" "); + + poUtil.getPropertieList().forEach(item -> { + if (!item.isPrimarykey()) { + sql.append(ifNotNullXML(item, item.getFieldNameByDB() + "=" + fieldDBWrite(item) + ",")); + } + }); + + sql.append(""); + + return sql.toString(); + } + + public StringBuilder updateSet(Collection paramUpdateSet) { + StringBuilder sql = new StringBuilder(); + List list = new ArrayList<>(); + sql.append("update ").append(po.getTableNameByDB()).append(" set "); + + paramUpdateSet.forEach( + item -> { + POPropertie info = poUtil.getPropertieByName(item); + list.add(info.getFieldNameByDB() + "=" + fieldDBWrite(info)); + } + ); + sql.append(StringUtils.join(list.toArray(), ",")); + return sql; + } + + + + public StringBuilder insert(Collection paramUpdateSet) { + List fields = new ArrayList<>(); + List values = new ArrayList<>(); + + StringBuilder sql = new StringBuilder(); + sql.append("insert into ").append(po.getTableNameByDB()).append("("); + paramUpdateSet.forEach( + item -> { + POPropertie info = poUtil.getPropertieByName(item); + fields.add(info.getFieldNameByDB()); + } + ); + sql.append(StringUtils.join(fields.toArray(), ",")); + sql.append(") values( "); + + paramUpdateSet.forEach( + item -> { + POPropertie info = poUtil.getPropertieByName(item); + values.add(fieldDBWrite(info)); + } + ); + sql.append(StringUtils.join(values.toArray(), ",")); + sql.append(")"); + + return sql; + } + + public StringBuilder deleteFrom() { + StringBuilder sql = new StringBuilder(); + sql.append("delete from "); + sql.append(po.getTableNameByDBAll()); + return sql; + } + + public String insertNotNullXML() { + StringBuilder sql = new StringBuilder(); + sql.append("insert into ").append(po.getTableNameByDB()).append(" ("); + sql.append(""); + poUtil.getPropertieList().forEach(item -> { + if (!item.isPrimarykey()) { + sql.append(ifNotNullXML(item, item.getFieldNameByDB() + ",")); + } + }); + sql.append(""); + + sql.append(") values ("); + sql.append(""); + + poUtil.getPropertieList().forEach(item -> { + if (!item.isPrimarykey()) { + sql.append(ifNotNullXML(item, fieldDBWrite(item) + ",")); + } + }); + sql.append(""); + + sql.append(")"); + + return sql.toString(); + } + + /** + * 写入字段处理 + * + * @param item + * @return + */ + private String fieldDBWrite(POPropertie item) { + String name = "#{" + item.getFieldName() + "}"; + if (!StringUtils.isEmpty(item.getDbType())) { + if ("datetime".equals(item.getDbType())) { + name = "from_unixtime(#{" + item.getFieldName() + "})"; + } + } + return name; + } + + /** + * 读取时字段处理 + * + * @param item + * @return + */ + private String fieldDBSelect(POPropertie item) { + String name = item.getFieldNameByDB(); + if (!StringUtils.isEmpty(item.getDbType())) { + if ("datetime".equals(item.getDbType())) { + name = "unix_timestamp(" + item.getFieldNameByDB() + ") as " + item.getFieldName(); + } + } else { + if (!item.getFieldName().equals(item.getFieldNameByDB())) { + name = item.getFieldNameByDB() + " as " + item.getFieldName(); + } + } + + return name; + } + + public String limit(int limit) { + return " limit " + limit; + } + + public String limit(int startIndex, int limit) { + return " limit " + startIndex + "," + limit; + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/annotation/DBType.java b/common/src/main/java/com/qmrz/mybatis/annotation/DBType.java new file mode 100644 index 0000000..b2a744b --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/annotation/DBType.java @@ -0,0 +1,13 @@ +package com.qmrz.mybatis.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface DBType { + String type(); + +} diff --git a/common/src/main/java/com/qmrz/mybatis/annotation/FieldName.java b/common/src/main/java/com/qmrz/mybatis/annotation/FieldName.java new file mode 100644 index 0000000..41a43bf --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/annotation/FieldName.java @@ -0,0 +1,9 @@ +package com.qmrz.mybatis.annotation; + +import java.lang.annotation.*; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface FieldName { + String name() default ""; +} diff --git a/common/src/main/java/com/qmrz/mybatis/annotation/ID.java b/common/src/main/java/com/qmrz/mybatis/annotation/ID.java new file mode 100644 index 0000000..055ac7e --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/annotation/ID.java @@ -0,0 +1,12 @@ +package com.qmrz.mybatis.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ID { + +} diff --git a/common/src/main/java/com/qmrz/mybatis/annotation/OrderByDefault.java b/common/src/main/java/com/qmrz/mybatis/annotation/OrderByDefault.java new file mode 100644 index 0000000..6939a27 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/annotation/OrderByDefault.java @@ -0,0 +1,13 @@ +package com.qmrz.mybatis.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface OrderByDefault { + boolean isasc() default false; + int index(); +} diff --git a/common/src/main/java/com/qmrz/mybatis/annotation/TableName.java b/common/src/main/java/com/qmrz/mybatis/annotation/TableName.java new file mode 100644 index 0000000..4ebf1d9 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/annotation/TableName.java @@ -0,0 +1,13 @@ +package com.qmrz.mybatis.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface TableName { + String name() default ""; + String schemasName() default ""; +} diff --git a/common/src/main/java/com/qmrz/mybatis/service/AbstractService.java b/common/src/main/java/com/qmrz/mybatis/service/AbstractService.java new file mode 100644 index 0000000..cf4d40e --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/service/AbstractService.java @@ -0,0 +1,91 @@ +package com.qmrz.mybatis.service; + +import com.qmrz.mybatis.BasePO; +import com.qmrz.mybatis.Mapper; +import com.qmrz.mybatis.sql.BaseWrapper; +import com.qmrz.mybatis.sql.sqlnode.UpdateParam; + +import java.util.List; +import java.util.function.Consumer; + +public abstract class AbstractService implements BaseService { + private Mapper baseMapper; + + public AbstractService(Mapper baseMapper){ + this.baseMapper = baseMapper; + } + + public void setBaseMapper(Mapper baseMapper) { + this.baseMapper = baseMapper; + } + + @Override + public List selectWrapper(Consumer wrapper) { + return baseMapper.selectWrapper(wrapper); + } + + @Override + public T selectOneWrapper(Consumer wrapper) { + return baseMapper.selectOneWrapper(wrapper); + } + + @Override + public Integer updateWrapper(Object param, Consumer wrapper) { + return baseMapper.updateWrapper(param, wrapper); + } + + @Override + public Integer deleteWrapper(Consumer wrapper) { + return baseMapper.deleteWrapper(wrapper); + } + + @Override + public List select(Object whereObject) { + return baseMapper.select(whereObject); + } + + @Override + public T selectOne(Object whereObject) { + return baseMapper.selectOne(whereObject); + } + + @Override + public Integer selectCount(Object whereObject) { + return baseMapper.selectCount(whereObject); + } + + @Override + public List selectAll() { + return baseMapper.selectAll(); + } + + @Override + public T selectByPrimaryKey(Object paramPrimaryKey) { + return baseMapper.selectByPrimaryKey(paramPrimaryKey); + } + + @Override + public int deleteByPrimaryKey(Object paramPrimaryKey) { + return baseMapper.deleteByPrimaryKey(paramPrimaryKey); + } + + @Override + public int delete(Object whereObject) { + return baseMapper.delete(whereObject); + } + + @Override + public int insert(T entity) { + return baseMapper.insert(entity); + } + + @Override + public int updateByPrimaryKey(Object paramMap) { + return baseMapper.updateByPrimaryKey(paramMap); + } + + @Override + public int update(UpdateParam updateParam) { + return baseMapper.update(updateParam); + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/service/BaseService.java b/common/src/main/java/com/qmrz/mybatis/service/BaseService.java new file mode 100644 index 0000000..7081847 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/service/BaseService.java @@ -0,0 +1,90 @@ +package com.qmrz.mybatis.service; + +import com.qmrz.mybatis.sql.BaseWrapper; +import com.qmrz.mybatis.sql.sqlnode.UpdateParam; + +import java.util.List; +import java.util.function.Consumer; + +public interface BaseService { + List selectWrapper(Consumer wrapper); + + T selectOneWrapper(Consumer wrapper); + + Integer updateWrapper(Object param, Consumer wrapper); + + Integer deleteWrapper(Consumer wrapper); + + /** + * 根据实体中的属性值进行查询,查询条件使用等号 + * + * @param whereObject map或实体 + * @return + */ + List select(Object whereObject); + + /** + * 根据实体中的属性进行查询,只能有一个返回值,有多个结果取第1个 + * + * @param whereObject map或实体 + * @return + */ + T selectOne(Object whereObject); + + /** + * 根据实体中的属性查询总数,查询条件使用等号 + * + * @param whereObject map或实体 + * @return + */ + Integer selectCount(Object whereObject); + + /** + * 查询全部结果 + * + * @return + */ + List selectAll(); + + /** + * 根据主键字段进行查询,查询条件使用等号 + * + * @param paramPrimaryKey map或实体 + * @return + */ + T selectByPrimaryKey(Object paramPrimaryKey); + + /** + * 根据主键字段进行删除,方法参数必须包含完整的主键属性 + * + * @param paramPrimaryKey map或实体 + * @return + */ + int deleteByPrimaryKey(Object paramPrimaryKey); + + /** + * 根据实体属性作为条件进行删除,查询条件使用等号 + * + * @param whereObject map或实体 + * @return + */ + int delete(Object whereObject); + + /** + * 保存一个实体,null的属性不会保存,会使用数据库默认值 + * + * @param entity map或实体 + * @return + */ + int insert(T entity); + + /** + * 根据主键更新实体全部字段,null值不会被更新 + * + * @param paramMap map或实体 + * @return + */ + int updateByPrimaryKey(Object paramMap); + + int update(UpdateParam updateParam); +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/AbsWrapperData.java b/common/src/main/java/com/qmrz/mybatis/sql/AbsWrapperData.java new file mode 100644 index 0000000..813ab1c --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/AbsWrapperData.java @@ -0,0 +1,131 @@ +package com.qmrz.mybatis.sql; + +import com.qmrz.mybatis.SqlUtil; + +import java.util.List; +import java.util.Map; + +/** + * 基础条件接口 + */ +public abstract class AbsWrapperData { + + /** + * 0:where 1:select 2:from 3:order 5:group 6:limit + * 20: update set + * 30: insert + * 40: delete + */ + private int wrapperStatus = 0; + + /** + * 当前块里的每个sql片段入栈时的条件组合方式 + * 0:无 1:and块 2:or块 + */ + private int conditionWhereStatus = 1; + + /** + * 当前块的条件组合方式 0:无 1:and块 2:or块 + */ + private int wrapperWhereStatus = 1; + + public int getWrapperStatus() { + return wrapperStatus; + } + + public int getConditionWhereStatus() { + return conditionWhereStatus; + } + + public int getWrapperWhereStatus() { + return wrapperWhereStatus; + } + + public abstract StringBuilder getSQL(); + + public StringBuilder getSQLLimit(){ + return new StringBuilder(); + } + + public abstract Map getParam(); + + private Class classPO; + protected SqlUtil sqlUtil; + + /** + * 总序号 + */ + private int index = 0; + + /** + * 当前嵌套块的序号 + */ + private int currentIndex = 0; + + protected void setIndex(int index) { + this.index = index; + renameByParamName(); + } + + protected int getIndex() { + return index; + } + + protected void setCurrentIndex(int currentIndex) { + this.currentIndex = currentIndex; + } + + public AbsWrapperData(int wrapperStatus, int wrapperWhereStatus, int conditionWhereStatus, Class classPO) { + this.wrapperStatus = wrapperStatus; + this.wrapperWhereStatus = wrapperWhereStatus; + this.conditionWhereStatus = conditionWhereStatus; + this.classPO = classPO; + this.sqlUtil = new SqlUtil(classPO); + } + + protected Class getClassPO() { + return classPO; + } + + protected abstract void renameByParamName(); + + /** + * 防止参数重复,重命名增加序号 + * + * @param fieldValue + */ + protected void renameByParamName(ConditionGeneralValue fieldValue) { + fieldValue.setName(fieldValue.getName() + "_" + index); + } + + protected void renameByParamName(List fieldValue) { + fieldValue.forEach(item -> item.setName(item.getName() + "_" + index)); + } + + /** + * 获取连接符 + */ + public String getLinkStr() { + String linkStr = " ";//每段sql的连接符,默认使用空格连接 + if (0 == currentIndex) { + return linkStr; + } + + if (0 == this.getWrapperStatus()) {//若where操作 + Integer whereStatus; + //是否是块包装器 + if (this instanceof BaseWrapper) { + whereStatus = this.getWrapperWhereStatus(); + } else { + whereStatus = this.getConditionWhereStatus(); + } + + if (1 == whereStatus) {//若and + linkStr = " and "; + } else if (2 == whereStatus) {//若or + linkStr = " or "; + } + } + return linkStr; + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/BaseWrapper.java b/common/src/main/java/com/qmrz/mybatis/sql/BaseWrapper.java new file mode 100644 index 0000000..67c159e --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/BaseWrapper.java @@ -0,0 +1,292 @@ +package com.qmrz.mybatis.sql; + +import com.qmrz.mybatis.sql.statement.*; + +import java.util.*; +import java.util.function.Consumer; + +public abstract class BaseWrapper extends AbsWrapperData implements IWrapper { + /** + * where 连接状态 + * 1: and块 + * 2: or块 + */ + //protected int whereStatus = 1; + private ConditionCount conditionsCount = new ConditionCount(0); + private int conditionsCurrentCount = 0; + private List conditions = new ArrayList<>(); + + protected void setConditionsCount(ConditionCount conditionsCount) { + this.conditionsCount = conditionsCount; + } + + public void addStatement(AbsWrapperData absWrapperData) { + absWrapperData.setIndex(conditionsCount.getCount()); + absWrapperData.setCurrentIndex(conditionsCurrentCount); + conditions.add(absWrapperData); + conditionsCount.increment(); + conditionsCurrentCount++; + } + + public List getConditions() { + return conditions; + } + + public BaseWrapper(int wrapperStatus, int wrapperWhereStatus, int conditionWhereStatus, Class classPO) { + super(wrapperStatus, wrapperWhereStatus, conditionWhereStatus, classPO); +// Class classPO = (Class) ((ParameterizedType) (this.getClass().getGenericInterfaces()[0])).getActualTypeArguments()[0]; +// POUtil.getPropertie(classPO); + } + + /** + * 此块的完整sql + * + * @return + */ + @Override + public StringBuilder getSQL() { + StringBuilder sql = new StringBuilder(); + if (conditions.size() == 0) { + return sql; + } + boolean kuohao = 0 == this.getWrapperStatus() && 0 != this.getWrapperWhereStatus(); + if (kuohao) {//where的条件时 + sql.append(this.getLinkStr()).append("("); + } + + conditions.forEach(item -> { + if (6 != item.getWrapperStatus()) {//6 limit + sql.append(item.getSQL()); + } + }); + + if (kuohao) {//where时 + sql.append(")"); + } + return sql; + } + + @Override + public StringBuilder getSQLLimit() { + StringBuilder sql = new StringBuilder(); + if (conditions.size() == 0) { + return sql; + } + + conditions.forEach(item -> { +// System.out.println("getSQLLimit"); + sql.append(item.getSQLLimit()); + }); + + return sql; + } + + /** + * 此块的所有参数 + * + * @return + */ + public Map getParam() { + Map param = new LinkedHashMap<>(); + conditions.forEach(item -> { + if (item.getParam() != null) { + for (Map.Entry entry : item.getParam().entrySet()) { + param.put(entry.getKey(), entry.getValue()); + } + } + }); + return param; + } + + @Override + protected void renameByParamName() { + //块包装器只是块,无参数,无逻辑 + } + + public BaseWrapper selectAllField() { + addStatement(new SelectAllField(getClassPO())); + return this; + } + + public BaseWrapper update(Map setParam) { + addStatement(new UpdateSet(getClassPO(), setParam)); + return this; + } + + public BaseWrapper delete() { + addStatement(new DeleteFrom(getClassPO())); + return this; + } + + public BaseWrapper from() { + addStatement(new FromTable(getClassPO())); + return this; + } + + public BaseWrapper limit(int limit) { + addStatement(new Limit(getClassPO(), limit, null)); + return this; + } + + public BaseWrapper limit(int limit1, int limit2) { + addStatement(new Limit(getClassPO(), limit1, limit2)); + return this; + } + + public BaseWrapper between(String fieldName, Object fieldValue1, Object fieldValue2) { + List param = new ArrayList<>(); + param.add(new ConditionGeneralValue(fieldName + "_between1", fieldValue1)); + param.add(new ConditionGeneralValue(fieldName + "_between2", fieldValue2)); + + ConditionBetween c = new ConditionBetween(getWrapperWhereStatus() + , getConditionWhereStatus(), getClassPO()); + c.setFiedName(fieldName); + c.setFieldValue(param); + return addWhere(c); + } + + public BaseWrapper in(String fieldName, List value) { + return in(fieldName, value.toArray()); + } + + public BaseWrapper in(String fieldName, Object ...value) { + if (value == null || value.length==0) { + return this; + } + List param = new ArrayList<>(); + for (int i=0;i"); + } + + public BaseWrapper gt(String fieldName, Object value) { + return addWhere(fieldName, "_gt", value, ">"); + } + + public BaseWrapper ge(String fieldName, Object value) { + return addWhere(fieldName, "_ge", value, ">="); + } + + public BaseWrapper lt(String fieldName, Object value) { + return addWhere(fieldName, "_lt", value, "<"); + } + + public BaseWrapper le(String fieldName, Object value) { + return addWhere(fieldName, "_le", value, "<="); + } + + public BaseWrapper or(Consumer action) { + return or(true, action); + } + + public BaseWrapper orderByDefault() { + addStatement(new OrderByDefault(getClassPO())); + return this; + } + + public BaseWrapper like(String fieldName, String fieldValue) { + if (fieldValue == null) { + return this; + } + + ConditionLike c = new ConditionLike(this.getWrapperWhereStatus() + , this.getConditionWhereStatus(), getClassPO()); + + c.setFiedName(fieldName); + c.setFieldValue(new ConditionGeneralValue(fieldName + "_like", fieldValue)); + return addWhere(c); + } + + public BaseWrapper or(boolean isConditionAnd, Consumer action) { + OrBlock w = new OrBlock(isConditionAnd, this.conditionsCount, this.getClassPO()); + this.addStatement(w); + action.accept(w);//执行嵌套的链式调用 + return this; + } + + + public BaseWrapper where() { + this.addStatement( + new StrWhere(this.getWrapperWhereStatus(), + this.getConditionWhereStatus() + , getClassPO()) + ); + return this; + } + + public BaseWrapper and(Consumer action) { + return and(true, action); + } + + public BaseWrapper and(boolean isConditionAnd, Consumer action) { + AndBlock w = new AndBlock(isConditionAnd, this.conditionsCount, this.getClassPO()); + this.addStatement(w); + action.accept(w);//执行嵌套的链式调用 + return this; + } + + /** + * 添加where语句 + * + * @param fieldName 参数名 + * @param paramSuffix 参数后缀 + * @param fieldValue 参数值 + * @param condition 操作符 = > < + * @return + */ + private BaseWrapper addWhere(String fieldName, String paramSuffix, Object fieldValue, String condition) { + ConditionGeneral c = new ConditionGeneral(this.getWrapperWhereStatus() + , this.getConditionWhereStatus(), getClassPO()); + + c.setFiedName(fieldName); + c.setFieldValue(new ConditionGeneralValue(fieldName + paramSuffix, fieldValue)); + c.setCondition(condition); + return addWhere(c); + } + + /** + * 添加where 条件语句 + * + * @param c + * @return + */ + private BaseWrapper addWhere(AbsWrapperData c) { + int conditionWhere = this.getConditionWhereStatus(); + + //若只第一次where,则增加一个where包装,使状态conditionWhere进入and/or状态 + if (conditionWhere != 1 && conditionWhere != 2) {//默认为and + WhereBlock ab = new WhereBlock(true, conditionsCount, getClassPO()); + ab.where().addStatement(c); + this.addStatement(ab); + return ab; + } + + this.addStatement(c); + return this; + } + + public BaseWrapper notoption() { + return this; + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/ConditionCount.java b/common/src/main/java/com/qmrz/mybatis/sql/ConditionCount.java new file mode 100644 index 0000000..1cae043 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/ConditionCount.java @@ -0,0 +1,18 @@ +package com.qmrz.mybatis.sql; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * 在整个链式(包含 入嵌套和出嵌套 的条件及块的增量统计) + */ +@Data +@AllArgsConstructor +public class ConditionCount { + private Integer count; + + public int increment(){ + this.count++; + return this.count; + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/ConditionGeneralValue.java b/common/src/main/java/com/qmrz/mybatis/sql/ConditionGeneralValue.java new file mode 100644 index 0000000..689254d --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/ConditionGeneralValue.java @@ -0,0 +1,17 @@ +package com.qmrz.mybatis.sql; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class ConditionGeneralValue { + /** + * sql参数名称 + */ + private String name; + /** + * sql参数值 + */ + private Object value; +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/IWrapper.java b/common/src/main/java/com/qmrz/mybatis/sql/IWrapper.java new file mode 100644 index 0000000..823e315 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/IWrapper.java @@ -0,0 +1,4 @@ +package com.qmrz.mybatis.sql; + +public interface IWrapper { +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/Wrapper.java b/common/src/main/java/com/qmrz/mybatis/sql/Wrapper.java new file mode 100644 index 0000000..a17da26 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/Wrapper.java @@ -0,0 +1,7 @@ +package com.qmrz.mybatis.sql; + +public class Wrapper extends BaseWrapper { + public Wrapper(Class classPO) { + super(-1, 0, 0,classPO); + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/WrapperResolve.java b/common/src/main/java/com/qmrz/mybatis/sql/WrapperResolve.java new file mode 100644 index 0000000..5a09b02 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/WrapperResolve.java @@ -0,0 +1,44 @@ +package com.qmrz.mybatis.sql; + +import com.qmrz.mybatis.sql.statement.AndBlock; +import com.qmrz.mybatis.sql.statement.ConditionGeneral; + +import java.util.*; + +public class WrapperResolve { + private BaseWrapper wrapper; + private StringBuffer sql = new StringBuffer(); +// private List fieldList = new ArrayList<>(); + private Map paramList = new LinkedHashMap<>(); + + public WrapperResolve(BaseWrapper wrapper) { + this.wrapper = wrapper; + } + + public void getSQL() { + getSQL(wrapper.getConditions()); + } + + private void getSQL(List list) { + if (list.size() == 0) { + return; + } + + sql.append("("); + list.forEach(item -> { + getSQL(item); + }); + sql.append(")"); + } + + private void getSQL(AbsWrapperData item) { + if (item instanceof ConditionGeneral) { + ConditionGeneral c = (ConditionGeneral) item; + sql.append(item.getSQL()); + paramList.put(c.getFieldValue().getName(), c.getFieldValue().getValue()); + + } else if (item instanceof BaseWrapper) { + getSQL(((AndBlock) item).getConditions()); + } + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/WrapperUtil.java b/common/src/main/java/com/qmrz/mybatis/sql/WrapperUtil.java new file mode 100644 index 0000000..8c22a82 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/WrapperUtil.java @@ -0,0 +1,23 @@ +package com.qmrz.mybatis.sql; + +import java.util.List; +import java.util.function.Consumer; + +public class WrapperUtil { + public static boolean hasWhere(BaseWrapper w) { + List list = w.getConditions(); + + boolean result = false; + for (AbsWrapperData absWrapperData : list) { + if (absWrapperData.getWrapperStatus() == 0) { + result = true; + break; + } + } + return result; + } + + public static Consumer consumer(Consumer w) { + return w; + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/sqlnode/SqlNodeWrapper.java b/common/src/main/java/com/qmrz/mybatis/sql/sqlnode/SqlNodeWrapper.java new file mode 100644 index 0000000..251dafa --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/sqlnode/SqlNodeWrapper.java @@ -0,0 +1,304 @@ +package com.qmrz.mybatis.sql.sqlnode; + +import com.qmrz.exception.ABException; +import com.qmrz.mybatis.BasePO; +import com.qmrz.mybatis.SqlUtil; +import com.qmrz.mybatis.sql.BaseWrapper; +import com.qmrz.mybatis.sql.Wrapper; +import com.qmrz.mybatis.sql.WrapperUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.binding.MapperMethod; +import org.apache.ibatis.scripting.xmltags.DynamicContext; +import org.apache.ibatis.scripting.xmltags.SqlNode; + +import java.util.Map; +import java.util.function.Consumer; + +@Slf4j +@SuppressWarnings("unchecked") +public class SqlNodeWrapper implements SqlNode { + /** + * select、update、delete + */ + private String option; + private Class classPO; + private SqlUtil sqlUtil; + + public SqlNodeWrapper(Class classPO, String option) { + this.option = option; + this.classPO = classPO; + this.sqlUtil = new SqlUtil(classPO); + } + + private void applySQL(DynamicContext context, StringBuilder sql, Map... param) { + context.appendSql(sql.toString()); + for (Map stringObjectMap : param) { + stringObjectMap.forEach((k, v) -> + context.bind(k, v) + ); + } + } + + @Override + public boolean apply(DynamicContext context) { + if (option.endsWith("Wrapper")) { + return applyWrapper(context);//包装器模式解析 + } else { + return applyGeneral(context);//普通模式解析 + } + } + + /** + * 普通模式解析 + * + * @param context + * @return + */ + public boolean applyGeneral(DynamicContext context) { + Object param = context.getBindings().get("_parameter"); + + switch (option) { + case "select": + select(context); + break; + + case "selectOne": + selectOne(context); + break; + + case "selectCount": + selectCountResolve(context); + break; + + case "update": + updateResolve(context); + break; + + case "delete": + deleteResolve(context); + break; + + case "insert": + insertResolve(context); + break; + } + return true; + } + + private void select(DynamicContext context) { + selectResolve(context, false); + } + + private void selectOne(DynamicContext context) { + selectResolve(context, true); + } + + private void selectResolve(DynamicContext context, boolean isone) { + Map param = (Map) context.getBindings().get("_parameter"); + StringBuilder sql = new StringBuilder(); + sql.append(sqlUtil.selectAllColumns()); + sql.append(sqlUtil.fromTable()); + sql.append(sqlUtil.whereByParam(param.keySet())); + sql.append(sqlUtil.orderByDefault()); + + if (isone) { + sql.append(" limit 1"); + } + + applySQL(context, sql, param); + } + + private void selectCountResolve(DynamicContext context) { + Map param = (Map) context.getBindings().get("_parameter"); + StringBuilder sql = new StringBuilder(); + sql.append(sqlUtil.selectCount()); + sql.append(sqlUtil.fromTable()); + sql.append(sqlUtil.whereByParam(param.keySet())); + + applySQL(context, sql, param); + } + + private void updateResolve(DynamicContext context) { + UpdateParam updateParam = (UpdateParam) context.getBindings().get("_parameter"); + Map set = updateParam.getSetData(); + Map param = (Map) updateParam.getWhereData(); + + if (param.size() == 0) { + throw new ABException("至少有一个查询条件"); + } + + StringBuilder sql = new StringBuilder(); + + sql.append(sqlUtil.updateSet(set.keySet())); + sql.append(sqlUtil.whereByParam(param.keySet())); + + applySQL(context, sql, set, param); + } + + private void deleteResolve(DynamicContext context) { + Map param = (Map) context.getBindings().get("_parameter"); + if (param.size() == 0) { + throw new ABException("至少有一个查询条件"); + } + + StringBuilder sql = new StringBuilder(); + sql.append(sqlUtil.deleteFrom()); + sql.append(sqlUtil.whereByParam(param.keySet())); + + applySQL(context, sql, param); + } + + private void insertResolve(DynamicContext context) { + Object _parameter = context.getBindings().get("_parameter"); + Map param; + if (_parameter instanceof BasePO) { +// param = new POUtil(classPO).getParamWriteNotNull(_parameter); + param = ((BasePO)_parameter)._getProxy().getSetList(); + } else { + param = (Map) _parameter; + } +// Map param = (Map) paramObj; + StringBuilder sql = new StringBuilder(); + sql.append(sqlUtil.insert(param.keySet())); + + applySQL(context, sql, param); + } + + /** + * 包装器模式解析 + * + * @param context + * @return + */ + public boolean applyWrapper(DynamicContext context) { + log.info("SqlNodeWrapper apply"); + BaseWrapper w = null; + switch (option) { + case "selectWrapper": + w = selectWrapper(context, false); + break; + case "selectOneWrapper": + w = selectWrapper(context, true); + break; + case "updateWrapper": + w = updateWrapper(context); + checkWhereWrapper(w); + break; + case "deleteWrapper": + w = deleteWrapper(context); + checkWhereWrapper(w); + break; + + case "select": + // w = deleteWrapper(context); + //checkWhereWrapper(w); + break; + default: + throw new ABException("功能 " + option + " 未实现"); + } + + log.info(w.getSQL().toString()); + log.info(w.getSQLLimit().toString()); + + log.info(String.valueOf(w.getParam())); + + //配置当前查询语句 + context.appendSql(w.getSQL().toString()); + context.appendSql(w.getSQLLimit().toString()); + //配置当前查询参数 + w.getParam().forEach((k, v) -> context.bind(k, v)); + + return true; + } + + private void checkWhereWrapper(BaseWrapper w) { + if (!WrapperUtil.hasWhere(w)) { + throw new ABException("必须有where条件"); + } + } + + /** + * 查询解析器 + * + * @param context + * @return + */ + private BaseWrapper selectWrapper(DynamicContext context, boolean isone) { + Object fn = context.getBindings().get("_parameter"); + BaseWrapper w = new Wrapper(classPO); + BaseWrapper result = w.selectAllField().from(); + + //执行表达式 + if (fn != null) { + ((Consumer) fn).accept(result); + } + result.orderByDefault(); + if (isone) { + result.limit(1); + } + return w; + } + + /** + * 更新解析器 + * + * @param context + * @return + */ + private BaseWrapper updateWrapper(DynamicContext context) { + Object _parameter = context.getBindings().get("_parameter"); + + Object fn; + Map paramUpdateSet; + if (_parameter instanceof UpdateParam) { + UpdateParam up = (UpdateParam) _parameter; + fn = up.getWhereData(); + paramUpdateSet = up.getSetData(); + } else { + //获取update的set参数,支持BasePO实体和map + MapperMethod.ParamMap paramMap = (MapperMethod.ParamMap) _parameter; + Object obj = paramMap.get("param1"); + if (obj instanceof Map) { + paramUpdateSet = (Map) obj; + } else if (obj instanceof BasePO) { + paramUpdateSet = ((BasePO) obj)._getProxy().getSetList(); +// new POUtil(obj.getClass()).getParamWriteNotNull(obj); + } else { + throw new ABException("参数不合法"); + } + + fn = paramMap.get("param2"); + } + + BaseWrapper w = new Wrapper(classPO); + + BaseWrapper result = w.update(paramUpdateSet); + log.info(String.valueOf(paramUpdateSet)); + + //执行表达式 + if (fn != null) { + ((Consumer) fn).accept(result); + } + + return w; + } + + /** + * 删除解析器 + * + * @param context + * @return + */ + private BaseWrapper deleteWrapper(DynamicContext context) { + Object fn = context.getBindings().get("_parameter"); + BaseWrapper w = new Wrapper(classPO); + BaseWrapper result = w.delete(); + + //执行表达式 + if (fn != null) { + ((Consumer) fn).accept(result); + } + + return w; + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/sqlnode/UpdateParam.java b/common/src/main/java/com/qmrz/mybatis/sql/sqlnode/UpdateParam.java new file mode 100644 index 0000000..d5d6db8 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/sqlnode/UpdateParam.java @@ -0,0 +1,13 @@ +package com.qmrz.mybatis.sql.sqlnode; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.Map; + +@Data +@AllArgsConstructor +public class UpdateParam { + private Map setData; + private Object whereData; +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/statement/AndBlock.java b/common/src/main/java/com/qmrz/mybatis/sql/statement/AndBlock.java new file mode 100644 index 0000000..c7ffe15 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/statement/AndBlock.java @@ -0,0 +1,18 @@ +package com.qmrz.mybatis.sql.statement; + +import com.qmrz.mybatis.sql.BaseWrapper; +import com.qmrz.mybatis.sql.ConditionCount; + +/** + * sql: 无,只包装作用 + */ +public class AndBlock extends BaseWrapper { + /** + * @param isConditionAnd + * @param index 嵌套时,序号继承到新块 + */ + public AndBlock(boolean isConditionAnd, ConditionCount index, Class classPO) { + super(0, 1, isConditionAnd ? 1 : 2, classPO); + this.setConditionsCount(index); + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/statement/ConditionBetween.java b/common/src/main/java/com/qmrz/mybatis/sql/statement/ConditionBetween.java new file mode 100644 index 0000000..82883db --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/statement/ConditionBetween.java @@ -0,0 +1,55 @@ +package com.qmrz.mybatis.sql.statement; + +import com.qmrz.exception.ABException; +import com.qmrz.mybatis.sql.AbsWrapperData; +import com.qmrz.mybatis.sql.ConditionGeneralValue; +import lombok.Data; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * sql: linkStr a between #{a1} and #{a2} + */ +@Data +public class ConditionBetween extends AbsWrapperData { + /** + * 条件左则字段名 + */ + private String fiedName; + + private List fieldValue; + + public ConditionBetween(int wrapperWhereStatus, int conditionWhereStatus, Class classPO) { + super(0, wrapperWhereStatus,conditionWhereStatus,classPO); + } + + @Override + public StringBuilder getSQL() { + if (fieldValue.size() != 2) { + throw new ABException("参数个数应该为2,目前是:" + fieldValue.size()); + } + + return new StringBuilder() + .append(this.getLinkStr()) + .append(fiedName).append(" between ") + .append("#{").append(fieldValue.get(0).getName()).append("}") + .append(" and ") + .append("#{").append(fieldValue.get(1).getName()).append("}"); + } + + @Override + public Map getParam() { + Map param = new LinkedHashMap<>(); + fieldValue.forEach(item->{ + param.put(item.getName(), item.getValue()); + }); + return param; + } + + @Override + protected void renameByParamName() { + this.renameByParamName(fieldValue); + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/statement/ConditionGeneral.java b/common/src/main/java/com/qmrz/mybatis/sql/statement/ConditionGeneral.java new file mode 100644 index 0000000..b476c2e --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/statement/ConditionGeneral.java @@ -0,0 +1,57 @@ +package com.qmrz.mybatis.sql.statement; + +import com.qmrz.mybatis.sql.AbsWrapperData; +import com.qmrz.mybatis.sql.ConditionGeneralValue; +import lombok.Data; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * sql: linkStr a=#{a} + */ +@Data +public class ConditionGeneral extends AbsWrapperData { + /** + * 条件左则字段名 + */ + private String fiedName; + /** + * 条件右侧参数名,及参数值 + */ + private ConditionGeneralValue fieldValue; + + private String condition; + + public ConditionGeneral(int wrapperWhereStatus, int conditionWhereStatus, Class classPO) { + super(0, wrapperWhereStatus, conditionWhereStatus, classPO); + } + + /** + * 格式 " and/or fieldname=#{paramname}" + * + * @return + */ + @Override + public StringBuilder getSQL() { + return new StringBuilder() + .append(this.getLinkStr()) + .append(fiedName).append(condition) + .append("#{").append(fieldValue.getName()).append("}"); + } + + @Override + public Map getParam() { + Map param = new LinkedHashMap<>(); +// if (fieldValue == null) { +// return param; +// } + param.put(fieldValue.getName(), fieldValue.getValue()); + return param; + } + + @Override + protected void renameByParamName() { + this.renameByParamName(fieldValue); + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/statement/ConditionIn.java b/common/src/main/java/com/qmrz/mybatis/sql/statement/ConditionIn.java new file mode 100644 index 0000000..a1743e4 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/statement/ConditionIn.java @@ -0,0 +1,56 @@ +package com.qmrz.mybatis.sql.statement; + +import com.qmrz.mybatis.sql.AbsWrapperData; +import com.qmrz.mybatis.sql.ConditionGeneralValue; +import lombok.Data; +import org.apache.commons.lang.StringUtils; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * sql: linkStr a in(#{a}) + */ +@Data +public class ConditionIn extends AbsWrapperData { + /** + * 条件左则字段名 + */ + private String fiedName; + + private List fieldValue; + + public ConditionIn(int wrapperWhereStatus, int conditionWhereStatus, Class classPO) { + super(0, wrapperWhereStatus,conditionWhereStatus,classPO); + } + + @Override + public StringBuilder getSQL() { + + List list = new ArrayList<>(); + fieldValue.forEach(item->list.add("#{"+item.getName()+"}")); + + StringBuilder sb= new StringBuilder() + .append(this.getLinkStr()) + .append(fiedName).append(" in (") + .append(StringUtils.join(list.toArray(),",")) + .append(")"); + return sb; + } + + @Override + public Map getParam() { + Map param = new LinkedHashMap<>(); + fieldValue.forEach(item->{ + param.put(item.getName(), item.getValue()); + }); + return param; + } + + @Override + protected void renameByParamName() { + this.renameByParamName(fieldValue); + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/statement/ConditionLike.java b/common/src/main/java/com/qmrz/mybatis/sql/statement/ConditionLike.java new file mode 100644 index 0000000..2675eb9 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/statement/ConditionLike.java @@ -0,0 +1,55 @@ +package com.qmrz.mybatis.sql.statement; + +import com.qmrz.mybatis.sql.AbsWrapperData; +import com.qmrz.mybatis.sql.ConditionGeneralValue; +import lombok.Data; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * sql: name like concat('%',#{name},'%') + */ +@Data +public class ConditionLike extends AbsWrapperData { + /** + * 条件左则字段名 + */ + private String fiedName; + /** + * 条件右侧参数名,及参数值 + */ + private ConditionGeneralValue fieldValue; + + public ConditionLike(int wrapperWhereStatus, int conditionWhereStatus, Class classPO) { + super(0, wrapperWhereStatus, conditionWhereStatus, classPO); + } + + /** + * 格式 " and/or fieldname=#{paramname}" + * + * @return + */ + @Override + public StringBuilder getSQL() { + return new StringBuilder() + .append(this.getLinkStr()) + .append(fiedName).append(" like") + .append(" concat('%',#{").append(fieldValue.getName()).append("},'%')"); + } + + @Override + public Map getParam() { + Map param = new LinkedHashMap<>(); + if (fieldValue == null) { + return param; + } + param.put(fieldValue.getName(), fieldValue.getValue()); + return param; + } + + @Override + protected void renameByParamName() { + this.renameByParamName(fieldValue); + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/statement/DeleteFrom.java b/common/src/main/java/com/qmrz/mybatis/sql/statement/DeleteFrom.java new file mode 100644 index 0000000..0567da7 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/statement/DeleteFrom.java @@ -0,0 +1,36 @@ +package com.qmrz.mybatis.sql.statement; + +import com.qmrz.mybatis.sql.AbsWrapperData; +import lombok.Data; + +import java.util.Map; + +/** + * sql: detele from tableName + */ +@Data +public class DeleteFrom extends AbsWrapperData { + private StringBuilder sql; + public DeleteFrom(Class classPO) { + super(40, 0, 0, classPO); + load(); + } + + private void load(){ + this.sql = sqlUtil.deleteFrom(); + } + + @Override + public StringBuilder getSQL() { + return new StringBuilder().append(this.sql); + } + + @Override + public Map getParam() { + return null; + } + + @Override + protected void renameByParamName() { + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/statement/FromTable.java b/common/src/main/java/com/qmrz/mybatis/sql/statement/FromTable.java new file mode 100644 index 0000000..84c444d --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/statement/FromTable.java @@ -0,0 +1,36 @@ +package com.qmrz.mybatis.sql.statement; + +import com.qmrz.mybatis.sql.AbsWrapperData; +import lombok.Data; + +import java.util.Map; + +/** + * sql: from tableName + */ +@Data +public class FromTable extends AbsWrapperData { + private StringBuilder sql; + public FromTable( Class classPO) { + super(2, 0, 0, classPO); + load(); + } + + private void load(){ + this.sql = sqlUtil.fromTable(); + } + + @Override + public StringBuilder getSQL() { + return new StringBuilder().append(this.sql); + } + + @Override + public Map getParam() { + return null; + } + + @Override + protected void renameByParamName() { + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/statement/Limit.java b/common/src/main/java/com/qmrz/mybatis/sql/statement/Limit.java new file mode 100644 index 0000000..707ab80 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/statement/Limit.java @@ -0,0 +1,57 @@ +package com.qmrz.mybatis.sql.statement; + +import com.qmrz.mybatis.sql.AbsWrapperData; +import lombok.Data; + +import java.util.Map; + +/** + * sql: from tableName + */ +@Data +public class Limit extends AbsWrapperData { + private Integer limit1; + private Integer limit2; + + public Limit(Class classPO, Integer limit1, Integer limit2) { + super(6, 0, 0, classPO); + this.limit1 = limit1; + this.limit2 = limit2; + load(); + } + + private void load() { + + } + + @Override + public StringBuilder getSQL() { + StringBuilder sql = new StringBuilder(); + if (limit1 != null && limit2 != null) { + sql.append(" limit " + limit1 + "," + limit2); + }else if (limit1 != null) { + sql.append(" limit " + limit1); + } + return sql; + } + + @Override + public StringBuilder getSQLLimit() { + StringBuilder sql = new StringBuilder(); + if (limit1 != null && limit2 != null) { + sql.append(" limit " + limit1 + "," + limit2); + }else if (limit1 != null) { + sql.append(" limit " + limit1); + } + return sql; + } + + @Override + public Map getParam() { + return null; + } + + @Override + protected void renameByParamName() { + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/statement/OrBlock.java b/common/src/main/java/com/qmrz/mybatis/sql/statement/OrBlock.java new file mode 100644 index 0000000..42cde2b --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/statement/OrBlock.java @@ -0,0 +1,18 @@ +package com.qmrz.mybatis.sql.statement; + +import com.qmrz.mybatis.sql.BaseWrapper; +import com.qmrz.mybatis.sql.ConditionCount; + +/** + * sql: 无,只包装作用 + */ +public class OrBlock extends BaseWrapper { + /** + * @param isConditionAnd + * @param index 嵌套时,序号继承到新块 + */ + public OrBlock(boolean isConditionAnd, ConditionCount index, Class classPO) { + super(0, 2, isConditionAnd ? 1 : 2, classPO); + this.setConditionsCount(index); + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/statement/OrderByDefault.java b/common/src/main/java/com/qmrz/mybatis/sql/statement/OrderByDefault.java new file mode 100644 index 0000000..b6010fe --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/statement/OrderByDefault.java @@ -0,0 +1,35 @@ +package com.qmrz.mybatis.sql.statement; + +import com.qmrz.mybatis.sql.AbsWrapperData; +import lombok.Data; + +import java.util.Map; + +/** + * sql: order by ... + */ +@Data +public class OrderByDefault extends AbsWrapperData { + public OrderByDefault(Class classPO) { + super(3, 0, 0, classPO); + load(); + } + + private void load(){ + + } + + @Override + public StringBuilder getSQL() { + return new StringBuilder().append(sqlUtil.orderByDefault()); + } + + @Override + public Map getParam() { + return null; + } + + @Override + protected void renameByParamName() { + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/statement/SelectAllField.java b/common/src/main/java/com/qmrz/mybatis/sql/statement/SelectAllField.java new file mode 100644 index 0000000..1859aae --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/statement/SelectAllField.java @@ -0,0 +1,36 @@ +package com.qmrz.mybatis.sql.statement; + +import com.qmrz.mybatis.sql.AbsWrapperData; +import lombok.Data; + +import java.util.Map; + +/** + * sql: select a,b,c .... + */ +@Data +public class SelectAllField extends AbsWrapperData { + private StringBuilder sql; + public SelectAllField(Class classPO) { + super(1, 0, 0, classPO); + load(); + } + + private void load(){ + this.sql = sqlUtil.selectAllColumns(); + } + + @Override + public StringBuilder getSQL() { + return new StringBuilder().append(this.sql); + } + + @Override + public Map getParam() { + return null; + } + + @Override + protected void renameByParamName() { + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/statement/StrWhere.java b/common/src/main/java/com/qmrz/mybatis/sql/statement/StrWhere.java new file mode 100644 index 0000000..0fdb869 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/statement/StrWhere.java @@ -0,0 +1,29 @@ +package com.qmrz.mybatis.sql.statement; + +import com.qmrz.mybatis.sql.AbsWrapperData; + +import java.util.Map; + +/** + * sql: where + */ +public class StrWhere extends AbsWrapperData { + public StrWhere(int wrapperWhereStatus, int conditionWhereStatus, Class classPO) { + super(0, wrapperWhereStatus, conditionWhereStatus, classPO); + } + + @Override + public StringBuilder getSQL() { + return new StringBuilder(" where"); + } + + @Override + public Map getParam() { + return null; + } + + @Override + protected void renameByParamName() { + + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/statement/UpdateSet.java b/common/src/main/java/com/qmrz/mybatis/sql/statement/UpdateSet.java new file mode 100644 index 0000000..bc142aa --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/statement/UpdateSet.java @@ -0,0 +1,37 @@ +package com.qmrz.mybatis.sql.statement; + +import com.qmrz.mybatis.sql.AbsWrapperData; + +import java.util.Map; + +/** + * sql: update tableName set a=#{a},b=#{b}.... + */ +public class UpdateSet extends AbsWrapperData { + private StringBuilder sql; + private Map paramUpdateSet; + public UpdateSet(Class classPO, Map paramUpdateSet) { + super(20, 0, 0, classPO); + this.paramUpdateSet = paramUpdateSet; + load(); + } + + private void load(){ + this.sql = sqlUtil.updateSet(paramUpdateSet.keySet()); + } + + @Override + public StringBuilder getSQL() { + return new StringBuilder(this.sql); + } + + @Override + public Map getParam() { + return paramUpdateSet; + } + + @Override + protected void renameByParamName() { + + } +} diff --git a/common/src/main/java/com/qmrz/mybatis/sql/statement/WhereBlock.java b/common/src/main/java/com/qmrz/mybatis/sql/statement/WhereBlock.java new file mode 100644 index 0000000..d9550d9 --- /dev/null +++ b/common/src/main/java/com/qmrz/mybatis/sql/statement/WhereBlock.java @@ -0,0 +1,18 @@ +package com.qmrz.mybatis.sql.statement; + +import com.qmrz.mybatis.sql.BaseWrapper; +import com.qmrz.mybatis.sql.ConditionCount; + +/** + * sql: 无,只包装作用 + */ +public class WhereBlock extends BaseWrapper { + /** + * @param isConditionAnd + * @param index 嵌套时,序号继承到新块 + */ + public WhereBlock(boolean isConditionAnd, ConditionCount index, Class classPO) { + super(0, 0, isConditionAnd ? 1 : 2, classPO); + this.setConditionsCount(index); + } +} diff --git a/common/src/main/java/com/qmrz/utils/CacheUtil.java b/common/src/main/java/com/qmrz/utils/CacheUtil.java new file mode 100644 index 0000000..aba448a --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/CacheUtil.java @@ -0,0 +1,27 @@ +package com.qmrz.utils; + +import net.sf.ehcache.Cache; +import net.sf.ehcache.CacheManager; +import net.sf.ehcache.Element; +import java.io.Serializable; + +public class CacheUtil { + public static Cache getCache() { + CacheManager cacheManager = SpringContextUtil.getBean(CacheManager.class); + Cache cache = cacheManager.getCache("userCache"); +// CacheConfiguration config = cache.getCacheConfiguration(); +// config.setTimeToIdleSeconds(60); +// config.setTimeToLiveSeconds(timeToLiveSeconds); + return cache; + } + + public static Element get(String name) { + return getCache().get(name); + } + + public static void put(String name, Serializable value, int timeToLive) { + Element el = new Element(name, value); + el.setTimeToLive(timeToLive); + getCache().put(el); + } +} diff --git a/common/src/main/java/com/qmrz/utils/ConvertUtil.java b/common/src/main/java/com/qmrz/utils/ConvertUtil.java new file mode 100644 index 0000000..6fb3444 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/ConvertUtil.java @@ -0,0 +1,334 @@ +package com.qmrz.utils; + +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.binary.Hex; + +import java.io.*; +import java.util.Collection; +import java.util.Map; + +/** + * 功能:转换编码 + * + * @author xiongliang + *

+ * mobile enterprise application platform + * Version 0.1 + */ +public class ConvertUtil { + public static final String LINE_SEPARATOR = System.getProperty("line.separator"); + private static final char[] BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray(); + /** + * 7位ASCII字符,也叫作ISO646-US、Unicode字符集的基本拉丁块 + */ + public static final String US_ASCII = "US-ASCII"; + /** + * ISO 拉丁字母表 No.1,也叫作 ISO-LATIN-1 + */ + public static final String ISO_8859_1 = "ISO-8859-1"; + /** + * 8 位 UCS 转换格式 + */ + public static final String UTF_8 = "UTF-8"; + /** + * 16 位 UCS 转换格式,Big Endian(最低地址存放高位字节)字节顺序 + */ + public static final String UTF_16BE = "UTF-16BE"; + /** + * 16 位 UCS 转换格式,Little-endian(最高地址存放低位字节)字节顺序 + */ + public static final String UTF_16LE = "UTF-16LE"; + /** + * 16 位 UCS 转换格式,字节顺序由可选的字节顺序标记来标识 + */ + public static final String UTF_16 = "UTF-16"; + /** + * 中文超大字符集 + */ + public static final String GBK = "GBK"; + /** + * 繁体中文 + */ + public static final String BIG_5 = "BIG5"; + + /** + * 是否是null + * + * @param term + * @return + */ + public static boolean isNull(String term) { + return !isNotNull(term); + } + + /** + * 是否是非null + * + * @param term + * @return + */ + public static boolean isNotNull(String term) { + if (term == null) return false; + if (term.trim().length() < 1) return false; + return true; + } + + /** + * 字符串编码转换的实现方法 + * + * @param strIn + * @param sourceCharset + * @param targetCharset + * @return + */ + public static String convertCharset(String strIn, String sourceCharset, String targetCharset) { + if (isNull(strIn)) + return strIn; + String strOut = null; + try { + byte[] c = strIn.getBytes(sourceCharset); + strOut = new String(c, targetCharset); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return strOut; + } + + /** + * 获得UTF8编码的字符串 + * + * @param gbkStr + * @return + */ + public static String convertGbkToUft8(String gbkStr) { + try { + return new String(convertGbkToUtf8Bytes(gbkStr), UTF_8); + } catch (UnsupportedEncodingException e) { + throw new InternalError(); + } + } + /** + * GBK转UTF-8编码 + * @param text + * @return + */ + /*public static String convertGbkToUft8(String text){ + String utf = null; + try { + String iso = new String(text.getBytes(UTF_8),ISO_8859_1); + utf = new String(iso.getBytes(ISO_8859_1),UTF_8); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return utf; + }*/ + + /** + * 获得UTF8编码的字节数组 + * + * @param gbkStr + * @return + */ + public static byte[] convertGbkToUtf8Bytes(String gbkStr) { + int n = gbkStr.length(); + byte[] utfBytes = new byte[3 * n]; + int k = 0; + for (int i = 0; i < n; i++) { + int m = gbkStr.charAt(i); + if (m < 128 && m >= 0) { + utfBytes[k++] = (byte) m; + continue; + } + utfBytes[k++] = (byte) (0xe0 | (m >> 12)); + utfBytes[k++] = (byte) (0x80 | ((m >> 6) & 0x3f)); + utfBytes[k++] = (byte) (0x80 | (m & 0x3f)); + } + if (k < utfBytes.length) { + byte[] tmp = new byte[k]; + System.arraycopy(utfBytes, 0, tmp, 0, k); + return tmp; + } + return utfBytes; + } + + /** + * 输入流转字符串 + * + * @param is + * @return + */ + public static String convertStreamToString(InputStream is) { + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + StringBuilder sb = new StringBuilder(); + String line = null; + try { + while ((line = reader.readLine()) != null) { + sb.append(line + LINE_SEPARATOR); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return sb.toString(); + } + + /** + * 半角转换成全角 + * + * @param input + * @return + */ + public static String convertSBC(String input) { + // 半角转全角 + char[] c = input.toCharArray(); + for (int i = 0; i < c.length; i++) { + if (c[i] == 32) { + c[i] = (char) 12288; + continue; + } + if (c[i] < 127) + c[i] = (char) (c[i] + 65248); + } + return new String(c); + } + + /** + * 全角转换成半角 + * + * @param input + * @return + */ + public static String convertDBC(String input) { + // 全角转 半角 + char[] c = input.toCharArray(); + for (int i = 0; i < c.length; i++) { + if (c[i] == 12288) { + c[i] = (char) 32; + continue; + } + if (c[i] > 65280 && c[i] < 65375) + c[i] = (char) (c[i] - 65248); + } + return new String(c); + } + + /** + * Hex编码. + */ + public static String convertEncodeHex(byte[] input) { + return Hex.encodeHexString(input); + } + + /** + * Hex解码. + */ + public static byte[] convertDecodeHex(String input) { + try { + return Hex.decodeHex(input.toCharArray()); + } catch (DecoderException e) { + throw new RuntimeException(e); + } + } + + /** + * Base64编码. + */ + public static String convertEncodeBase64(byte[] input) { + return Base64.encodeBase64String(input); + } + + /** + * Base64编码, URL安全(将Base64中的URL非法字符'+'和'/'转为'-'和'_', 见RFC3548). + */ + public static String convertEncodeUrlSafeBase64(byte[] input) { + return Base64.encodeBase64URLSafeString(input); + } + + /** + * Base64解码. + */ + public static byte[] convertDecodeBase64(String input) { + return Base64.decodeBase64(input); + } + + /** + * Base62编码。 + */ + public static String convertEncodeBase62(byte[] input) { + char[] chars = new char[input.length]; + for (int i = 0; i < input.length; i++) { + chars[i] = BASE62[((input[i] & 0xFF) % BASE62.length)]; + } + return new String(chars); + } + + /** + * 输入或读取数据库之前的转换 + * @param src + * @return + */ + public static String toReadStr(Object src) { + String s = ""; //$NON-NLS-1$ + if (src != null) { + // 读字符编码转换 + s = src.toString().trim(); + s = s.replaceAll("<", "<"); //$NON-NLS-1$ //$NON-NLS-2$ + s = s.replaceAll(">", ">"); //$NON-NLS-1$ //$NON-NLS-2$ + s = s.replaceAll("\"", "“"); //$NON-NLS-1$ //$NON-NLS-2$ + } + return s; + } + /** + * 字符串转换成整形 + * @param src + * @return + */ + public static Integer toInteger(Object src) { + String s = toReadStr(src); + Integer i = 0; + if (!"".equals(s)) { //$NON-NLS-1$ + try { + i = Integer.parseInt(s); + } catch (NumberFormatException e) { + i = 0; + } + } + return i; + } + public static boolean isEmpty(Object pObj) { + if (pObj == null) + return true; + if (pObj.equals("")) + return true; + if (pObj instanceof String) { + if (((String) pObj).length() == 0) { + return true; + } + } else if (pObj instanceof Collection) { + if (((Collection) pObj).size() == 0) { + return true; + } + } else if (pObj instanceof Map) { + if (((Map) pObj).size() == 0) { + return true; + } + } + return false; + } + + public static boolean isEmptyError(Map map,final String... headers) { + for (int i = 0; i < headers.length; i++) { + if (isEmpty(map.get(headers[i]))) { + return true; + } + } + return false; + } + +} diff --git a/common/src/main/java/com/qmrz/utils/DBHelper.java b/common/src/main/java/com/qmrz/utils/DBHelper.java new file mode 100644 index 0000000..d60b598 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/DBHelper.java @@ -0,0 +1,184 @@ +package com.qmrz.utils; + +import org.apache.ibatis.cursor.Cursor; +import org.apache.ibatis.executor.BatchResult; +import org.apache.ibatis.session.Configuration; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.apache.ibatis.session.SqlSession; +import org.mybatis.spring.SqlSessionTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.sql.Connection; +import java.util.List; +import java.util.Map; + +/** + * 基于mybatis的数据库操作类,无需mapper接口,直接调用xml的sql + */ +@Component +public class DBHelper implements SqlSession { + SqlSessionTemplate sql; + private static final String statementPrefix = "com.qmrz.domain.mapper."; + + public String getStatement(String id) { + return statementPrefix + id; + } + + @Autowired + public DBHelper(SqlSessionTemplate sqlSessionTemplate) { + this.sql = sqlSessionTemplate; + } + + @Override + public T selectOne(String statement) { + return sql.selectOne(getStatement(statement)); + } + + @Override + public T selectOne(String statement, Object parameter) { + return sql.selectOne(getStatement(statement), parameter); + } + + @Override + public List selectList(String statement) { + return sql.selectList(getStatement(statement)); + } + + @Override + public List selectList(String statement, Object parameter) { + return sql.selectList(getStatement(statement), parameter); + } + + @Override + public List selectList(String statement, Object parameter, RowBounds rowBounds) { + return sql.selectList(getStatement(statement), parameter, rowBounds); + } + + @Override + public Map selectMap(String statement, String mapKey) { + return sql.selectMap(getStatement(statement), mapKey); + } + + @Override + public Map selectMap(String statement, Object parameter, String mapKey) { + return sql.selectMap(getStatement(statement), parameter, mapKey); + } + + @Override + public Map selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) { + return sql.selectMap(getStatement(statement), parameter, mapKey, rowBounds); + } + + @Override + public Cursor selectCursor(String statement) { + return sql.selectCursor(getStatement(statement)); + } + + @Override + public Cursor selectCursor(String statement, Object parameter) { + return sql.selectCursor(getStatement(statement), parameter); + } + + @Override + public Cursor selectCursor(String statement, Object parameter, RowBounds rowBounds) { + return sql.selectCursor(getStatement(statement), parameter, rowBounds); + } + + @Override + public void select(String statement, Object parameter, ResultHandler handler) { + sql.select(getStatement(statement), parameter, handler); + } + + @Override + public void select(String statement, ResultHandler handler) { + sql.select(getStatement(statement), handler); + } + + @Override + public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { + sql.select(getStatement(statement), parameter, rowBounds, handler); + } + + @Override + public int insert(String statement) { + return sql.insert(getStatement(statement)); + } + + @Override + public int insert(String statement, Object parameter) { + return sql.insert(getStatement(statement), parameter); + } + + @Override + public int update(String statement) { + return sql.update(getStatement(statement)); + } + + @Override + public int update(String statement, Object parameter) { + return sql.update(getStatement(statement), parameter); + } + + @Override + public int delete(String statement) { + return sql.delete(getStatement(statement)); + } + + @Override + public int delete(String statement, Object parameter) { + return sql.delete(getStatement(statement), parameter); + } + + @Override + public void commit() { + sql.commit(); + } + + @Override + public void commit(boolean force) { + sql.commit(force); + } + + @Override + public void rollback() { + sql.rollback(); + } + + @Override + public void rollback(boolean force) { + sql.rollback(force); + } + + @Override + public List flushStatements() { + return sql.flushStatements(); + } + + @Override + public void close() { + sql.close(); + } + + @Override + public void clearCache() { + sql.clearCache(); + } + + @Override + public Configuration getConfiguration() { + return sql.getConfiguration(); + } + + @Override + public T getMapper(Class type) { + return sql.getMapper(type); + } + + @Override + public Connection getConnection() { + return sql.getConnection(); + } + +} diff --git a/common/src/main/java/com/qmrz/utils/DateTimeUtil.java b/common/src/main/java/com/qmrz/utils/DateTimeUtil.java new file mode 100644 index 0000000..94a0b12 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/DateTimeUtil.java @@ -0,0 +1,145 @@ +package com.qmrz.utils; + +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAccessor; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +public class DateTimeUtil { + private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + private static final DateTimeFormatter dtfDate = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + private static ThreadLocal ThreadDateTime = new ThreadLocal(); + + //日期时间类型格式 + private static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + private static final DateTimeFormatter dtfGMT = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH) + .withZone(TimeZone.getTimeZone("GMT").toZoneId()); + + public static String format(TemporalAccessor dateTime) { + return dtf.format(dateTime); + } + + public static String format(TemporalAccessor dateTime, String format) { + return DateTimeFormatter.ofPattern(format).format(dateTime); + } + + public static String formatDate(TemporalAccessor dateTime) { + return dtfDate.format(dateTime); + } + + public static String datePlus(String date,int days){ + //结束日期需要加一天,api同步时不包含结束日期 + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + LocalDateTime local = LocalDateTime.from(dtf.parse(date+" 00:00:00")).plusDays(days); + return formatDate(local); + } + +// public static String formatBySecond(long second) { +// return dtf.format(LocalDateTime.ofEpochSecond(second, 0, ZoneOffset.ofHours(8))); +// } +// +// public static String formatDataBySecond(long second) { +// return dtfDate.format(LocalDateTime.ofEpochSecond(second, 0, ZoneOffset.ofHours(8))); +// } + + public static String formatGMTBySecond(long second) { + return dtfGMT.format(LocalDateTime.ofEpochSecond(second, 0 + , ZoneOffset.ofHours(0))); + } + + /** + * 获取当前日期 毫秒 + * + * @return + */ + public static long getTimeInMillis() { + Calendar now = Calendar.getInstance(); + + return now.getTimeInMillis(); + } + + /** + * 时间字符串 解析为 时间戳(毫秒) + * + * @param time 时间,如:2018-08-06 04:52:50 127 + * @param format 时间格式,如:yyyy-MM-dd HH:mm:ss SSS + * @param zone 时区,如:ZoneOffset.ofHours(8) + * @return + */ + public static Long getTimeInMillis(String time, String format, ZoneOffset zone) { + Instant instant = getInstant(time, format, zone); + return instant.toEpochMilli(); + } + + /** + * 获取当前日期 秒 + * + * @return + */ + public static long getTimeInSeconds() { + return getTimeInMillis() / 1000L; + } + + /** + * 时间字符串 解析为 时间戳(秒) + * + * @param time 时间,如:2018-08-06 04:52:50 127 + * @param format 时间格式,如:yyyy-MM-dd HH:mm:ss SSS + * @param zone 时区,如:ZoneOffset.ofHours(8) + * @return + */ + public static Long getTimeInSeconds(String time, String format, ZoneOffset zone) { + Instant instant = getInstant(time, format, zone); + return instant.getEpochSecond(); + } + + /** + * 时间字符串 解析为 时刻对象 + * + * @param time + * @param format + * @param zone + * @return + */ + public static Instant getInstant(String time, String format, ZoneOffset zone) { + DateTimeFormatter df = DateTimeFormatter.ofPattern(format); + Instant instant = LocalDateTime.parse(time, df).atZone(zone).toInstant(); + return instant; + } + + /** + * 获取时刻 时间戳 转 时刻 + * + * @param timestamp + * @return + */ + public static Instant getInstant(long timestamp) { + return Instant.ofEpochSecond(timestamp); + } + + /** + * 获取当前日期时间 + * + * @return 返回当前时间的字符串值 + */ + public static String currentDateTime() { + return DateTimeInstance().format(new Date()); + } + + private static SimpleDateFormat DateTimeInstance() { + SimpleDateFormat df = ThreadDateTime.get(); + if (df == null) { + df = new SimpleDateFormat(DATETIME_FORMAT); + ThreadDateTime.set(df); + } + return df; + } + +} diff --git a/common/src/main/java/com/qmrz/utils/ExportPOIUtils.java b/common/src/main/java/com/qmrz/utils/ExportPOIUtils.java new file mode 100644 index 0000000..4c0b2ad --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/ExportPOIUtils.java @@ -0,0 +1,191 @@ +package com.qmrz.utils; +import java.awt.image.BufferedImage; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.imageio.ImageIO; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; + +import org.apache.ibatis.reflection.MetaObject; +import org.apache.ibatis.reflection.SystemMetaObject; +import org.apache.poi.hssf.usermodel.HSSFClientAnchor; +import org.apache.poi.hssf.usermodel.HSSFPatriarch; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; + + +public class ExportPOIUtils { + //参数说明: fileName:文件名 projects:对象集合 columnNames: 列名 keys: map中的key + public static void start_download(HttpServletResponse response, String fileName, List projects, + String[] columnNames, String[] keys) throws IOException { + + //将集合中对象的属性 对应到 List> + List> list=createExcelRecord(projects, keys); + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + try { + //将转换成的Workbook对象通过流形式下载 + createWorkBook(list,keys,columnNames).write(os); + } catch (IOException e) { + e.printStackTrace(); + } + byte[] content = os.toByteArray(); + InputStream is = new ByteArrayInputStream(content); + // 设置response参数,可以打开下载页面 + response.reset(); + response.setContentType("application/vnd.ms-excel;charset=utf-8"); + response.setHeader("Content-Disposition", "attachment;filename="+ new String((fileName + ".xls").getBytes(), "utf-8")); + ServletOutputStream out = response.getOutputStream(); + BufferedInputStream bis = null; + BufferedOutputStream bos = null; + try { + bis = new BufferedInputStream(is); + bos = new BufferedOutputStream(out); + byte[] buff = new byte[2048]; + int bytesRead; + while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) { + bos.write(buff, 0, bytesRead); + } + + } catch (final IOException e) { + throw e; + } finally { + if (bis != null) + bis.close(); + if (bos != null) + bos.close(); + } + } + + private static List> createExcelRecord(List projects, String[] keys) { + List> listmap = new ArrayList>(); + Map map = new HashMap(); + map.put("sheetName", "sheet"); + listmap.add(map); + Object project=null; + for (int j = 0; j < projects.size(); j++) { + project=projects.get(j); + Map mapValue = new HashMap(); + for(int i=0; i> list,String []keys,String columnNames[]) { + // 创建excel工作簿 + Workbook wb = new HSSFWorkbook(); + // 创建第一个sheet(页),并命名 + Sheet sheet = wb.createSheet(list.get(0).get("sheetName").toString()); + // 手动设置列宽。第一个参数表示要为第几列设;,第二个参数表示列的宽度,n为列高的像素数。 + for(int i=0;i 0) || (len < value.length())) ? value.substring(st, len) : value; + } + + /** + * 是否来自ajax请求 + * + * @param requestContent + * @return + */ + public static Boolean requestIsAjax(String requestContent) { + if (requestContent == null || requestContent.length() == 0) { + return false; + } + JSONObject o = null; + try { + o = Json.toObject(requestContent); + } catch (Throwable e) { + return false; + } + + if (!o.containsKey("ajax")) { + return false; + } + return new Integer("1").equals(o.get("ajax")); + } + + /** + * 是否来自ajax请求 + * + * @param inputStream + * @return + */ + public static Boolean requestIsAjax(InputStream inputStream) { + String input = StreamUtil.inputToString(inputStream).toString(); + return requestIsAjax(input); + } + + public static String urlEnodeUTF8(String str) { + String result = str; + try { + result = URLEncoder.encode(str, "UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + + /** + * 获取一定长度的随机字符串 + * + * @param length 指定字符串长度 + * @return 一定长度的字符串 + */ + public static String getRandomString(int length) { + String base = "abcdefghijklmnopqrstuvwxyz0123456789"; + Random random = new Random(); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < length; i++) { + int number = random.nextInt(base.length()); + sb.append(base.charAt(number)); + } + return sb.toString(); + } + + /** + * 生成指定位数数字 + * + * @param length + * @return + */ + public static String getRandomNumber(int length) { + // 生成随机n位码 + String s = ""; + while (s.length() < 4) { + s += (int) (Math.random() * 10); + } + return s; + } + + /** + * 生成唯一字符串,去除横杆 + * + * @return + */ + public static String getUUID() { + return UUID.randomUUID().toString().replace("-", ""); + } + + /** + * 对象序列化为字符串 + * + * @return + */ + public static String objectSerialize(Object obj) { + ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(); + try { + ObjectOutputStream outputStream = new ObjectOutputStream(byteOutput); + outputStream.writeObject(obj); + String str = byteOutput.toString("ISO-8859-1"); + + return str; + } catch (IOException e) { + e.printStackTrace(); + return "error:" + e.getMessage(); + } + } + + /** + * 字符串反序列化为对象 + * + * @param str + * @return + */ + public static Object objectDeserialize(String str) { + try { + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(str.getBytes("ISO-8859-1")); + ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); + Object obj = objectInputStream.readObject(); + return obj; + } catch (Exception e) { + e.printStackTrace(); + return "error:" + e.getMessage(); + } + } + + /** + * 首字母大写 + * + * @param str + * @return + */ + public static String firstUpperCase(String str) { + if (str == null) { + return null; + } + if (0 == str.length()) { + return ""; + } + + return str.substring(0, 1).toUpperCase() + str.substring(1); + } + + /** + * 首字母大写(高性能,待验证) + * + * @param str + * @return + */ + public static String firstUpperCase2(String str) { + if (str == null) { + return null; + } + if (0 == str.length()) { + return ""; + } + + char[] arr = str.toCharArray(); + arr[0] -= 32; + return String.valueOf(arr); + } + + /** + * 手动metaspace扩容,以便即时触发,释放OC内存(非回收) + * + * @param cou 扩容数量 + * @param sleepSecond sleepSecond 秒后执行 + */ + public static void addMetaspace(int cou, long sleepSecond) { + log.info("准备metaspace扩容:" + cou + "个"); + try { + //5秒后发生 + Thread.sleep(sleepSecond * 1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + StringBuffer sb = new StringBuffer(); + sb.append("package com.qmrz.utils.classload;\n"); + sb.append("public class MetaspaceEmptyCapacityExpansion"); + + StringBuffer sb2 = new StringBuffer(); + sb2.append(" {\n"); + sb2.append("private static String str = String.valueOf(System.currentTimeMillis());\n"); + sb2.append("public void test(){}\n"); + for (int i = 0; i < 1000; i++) { + sb2.append("public void test" + String.valueOf(i) + "(){}\n"); + } + sb2.append("}"); + + List> claList = new ArrayList<>(); + JavaStringCompiler compiler = new JavaStringCompiler(); + for (int i = 0; i < cou; i++) { + String strI = String.valueOf(i); + StringBuffer tmp = new StringBuffer(); + tmp.append(sb); + tmp.append(strI); + tmp.append(sb2); + + Map results = null; + try { + results = compiler.compile("MetaspaceEmptyCapacityExpansion" + strI + ".java", tmp.toString()); + } catch (IOException e) { + e.printStackTrace(); + } + + try { + Class clazz = compiler.loadClass("com.qmrz.utils.classload.MetaspaceEmptyCapacityExpansion" + strI, results); + claList.add(clazz); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + tmp = null; + log.info("忽略警告 " + i); + } + + claList.clear(); + claList = null; + } +} diff --git a/common/src/main/java/com/qmrz/utils/FreemarkerExceptionHandler.java b/common/src/main/java/com/qmrz/utils/FreemarkerExceptionHandler.java new file mode 100644 index 0000000..e1cb729 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/FreemarkerExceptionHandler.java @@ -0,0 +1,14 @@ +package com.qmrz.utils; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Configuration; + +@Slf4j +@Configuration +public class FreemarkerExceptionHandler { +// @Bean +// freemarker.template.Configuration freeMarkerConfig() { +// return +// } + +} diff --git a/common/src/main/java/com/qmrz/utils/Identities.java b/common/src/main/java/com/qmrz/utils/Identities.java new file mode 100644 index 0000000..f875dba --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/Identities.java @@ -0,0 +1,80 @@ +package com.qmrz.utils; + +import java.security.SecureRandom; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicLong; + +public class Identities { + private static SecureRandom random = new SecureRandom(); + private static AtomicLong atomicLongID = new AtomicLong(10000L); + + public static String uuid() { + return UUID.randomUUID().toString(); + } + + public static String uuid2() { + return UUID.randomUUID().toString().replaceAll("-", ""); + } + + public static long randomLong() { + return Math.abs(random.nextLong()); + } + + public static String randomBase62(int length) { + byte[] randomBytes = new byte[length]; + random.nextBytes(randomBytes); + return ConvertUtil.convertEncodeBase62(randomBytes); + } + + /** + * 连接对象 + * @param objs + * @return + */ + public static String concat(Object...objs) { + + if(objs==null || objs.length<1)return ""; + StringBuffer sb = new StringBuffer(); + for(Object obj : objs){ + sb.append(obj==null?"":obj.toString()); + } + return sb.toString(); + } + + // 将date类型转换为字符串yyyy年MM月dd日 + public static String changeDateTOStr5(Date date,String pattern) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); + return getDateToStr(date, sdf); + } + private static String getDateToStr(Date date, SimpleDateFormat sdf) { + String dateStr = null; + try { + dateStr = sdf.format(date); + return dateStr; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public static String getTimeMillisSequence() { + long nanoTime = System.nanoTime(); + String preFix = null; + if (nanoTime < 0L) { + preFix = "A"; + nanoTime = nanoTime + 9223372036854775807L + 1L; + } else { + preFix = "Z"; + } + String nanoTimeStr = String.valueOf(nanoTime); + int difBit = String.valueOf(9223372036854775807L).length() - nanoTimeStr.length(); + for (int i = 0; i < difBit; i++) { + preFix = concat(new Object[]{preFix, "0"}); + } + long last = atomicLongID.getAndIncrement() % 10000L + 10000L; + return concat(new Object[]{changeDateTOStr5(new Date(), "yyyyMMddHHmmssSSS"), preFix, nanoTimeStr, Long.valueOf(last)}); + } +} diff --git a/common/src/main/java/com/qmrz/utils/ImageUtil.java b/common/src/main/java/com/qmrz/utils/ImageUtil.java new file mode 100644 index 0000000..17b76d0 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/ImageUtil.java @@ -0,0 +1,39 @@ +package com.qmrz.utils; + +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; + +public class ImageUtil { + public static BufferedImage toBufferedImage(Image image) { + if (image instanceof BufferedImage) { + return (BufferedImage) image; + } + // This code ensures that all the pixels in the image are loaded + image = new ImageIcon(image).getImage(); + BufferedImage bimage = null; + GraphicsEnvironment ge = GraphicsEnvironment + .getLocalGraphicsEnvironment(); + try { + int transparency = Transparency.OPAQUE; + GraphicsDevice gs = ge.getDefaultScreenDevice(); + GraphicsConfiguration gc = gs.getDefaultConfiguration(); + bimage = gc.createCompatibleImage(image.getWidth(null), + image.getHeight(null), transparency); + } catch (HeadlessException e) { + // The system does not have a screen + } + if (bimage == null) { + // Create a buffered image using the default color model + int type = BufferedImage.TYPE_INT_RGB; + bimage = new BufferedImage(image.getWidth(null), + image.getHeight(null), type); + } + // Copy image to buffered image + Graphics g = bimage.createGraphics(); + // Paint the image onto the buffered image + g.drawImage(image, 0, 0, null); + g.dispose(); + return bimage; + } +} diff --git a/common/src/main/java/com/qmrz/utils/JWTUtil.java b/common/src/main/java/com/qmrz/utils/JWTUtil.java new file mode 100644 index 0000000..559aacc --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/JWTUtil.java @@ -0,0 +1,38 @@ +package com.qmrz.utils; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.DecodedJWT; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +public class JWTUtil { + public static String sign(String userName, String userID, String secret, long expireTime) { + Date date = new Date(System.currentTimeMillis() + expireTime); + Algorithm algorithm = Algorithm.HMAC256(secret); + Map header = new HashMap<>(); + header.put("type", "jwt"); + header.put("alg", "HS256"); + + String result = JWT.create().withHeader(header) + .withClaim("loginName", userName) + .withClaim("userID", userID) + .withExpiresAt(date) + .sign(algorithm); + return result; + } + + public static boolean verify(String secret, String token) { + Algorithm algorithm = Algorithm.HMAC256(secret); + JWTVerifier verifier = JWT.require(algorithm).build(); + try { + DecodedJWT decodedJWT = verifier.verify(token); + return true; + } catch (Exception e) { + return false; + } + } +} diff --git a/common/src/main/java/com/qmrz/utils/Json.java b/common/src/main/java/com/qmrz/utils/Json.java new file mode 100644 index 0000000..ffc8392 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/Json.java @@ -0,0 +1,23 @@ +package com.qmrz.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; + +public class Json { + public static JSONObject toObject(String str){ + return JSON.parseObject(str); + } + + public static JSONArray toArray(String str){ + return JSON.parseArray(str); + } + + public static Object parse(String str){ + return JSON.parse(str); + } + + public static String toString(Object obj){ + return JSON.toJSONString(obj); + } +} diff --git a/common/src/main/java/com/qmrz/utils/ListPageUtil.java b/common/src/main/java/com/qmrz/utils/ListPageUtil.java new file mode 100644 index 0000000..a08623e --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/ListPageUtil.java @@ -0,0 +1,45 @@ +package com.qmrz.utils; + +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 集合分页 + */ +@Slf4j +public class ListPageUtil { + private List data; + private int pageSize; + + private int pageCount; + private int rowCount; + + public int getPageCount() { + return pageCount; + } + + public ListPageUtil(List data, int pageSize){ + this.data = data; + this.rowCount = data.size(); + this.pageSize = pageSize; + this.pageCount = this.rowCount / pageSize; + if (this.rowCount % pageSize != 0) { + this.pageCount++; + } + } + + public List start(int pageIndex) { + int fromIndex = this.pageSize * (pageIndex - 1); + int toIndex = fromIndex + this.pageSize; + if (toIndex > this.rowCount) { + toIndex = this.rowCount; + } + if (pageIndex > this.pageCount) { + fromIndex = 0; + toIndex = 0; + } + log.info("pageIndex="+pageIndex+", fromIndex="+fromIndex+", toIndex="+toIndex+","); + return this.data.subList(fromIndex, toIndex); + } +} diff --git a/common/src/main/java/com/qmrz/utils/MD5Util.java b/common/src/main/java/com/qmrz/utils/MD5Util.java new file mode 100644 index 0000000..902ad78 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/MD5Util.java @@ -0,0 +1,55 @@ +package com.qmrz.utils; + + +import java.security.MessageDigest; + +public class MD5Util { + + private static String byteArrayToHexString(byte b[]) { + StringBuffer resultSb = new StringBuffer(); + for (int i = 0; i < b.length; i++) + resultSb.append(byteToHexString(b[i])); + + return resultSb.toString(); + } + + private static String byteToHexString(byte b) { + int n = b; + if (n < 0) + n += 256; + int d1 = n / 16; + int d2 = n % 16; + return hexDigits[d1] + hexDigits[d2]; + } + + public static String md5Encode(String origin, String charsetname) { + String resultString = null; + try { + resultString = new String(origin); + MessageDigest md = MessageDigest.getInstance("MD5"); + if (charsetname == null || "".equals(charsetname)) + resultString = byteArrayToHexString(md.digest(resultString + .getBytes())); + else + resultString = byteArrayToHexString(md.digest(resultString + .getBytes(charsetname))); + } catch (Exception exception) { + } + return resultString; + } + + public static String getMD5Code(String origin) { + String resultString = null; + try { + resultString = new String(origin); + MessageDigest md = MessageDigest.getInstance("MD5"); + resultString = byteArrayToHexString(md.digest(resultString + .getBytes("utf-8"))); + } catch (Exception exception) { + } + return resultString; + } + private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5", + "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; + +} diff --git a/common/src/main/java/com/qmrz/utils/MapChain.java b/common/src/main/java/com/qmrz/utils/MapChain.java new file mode 100644 index 0000000..a5f9c39 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/MapChain.java @@ -0,0 +1,37 @@ +package com.qmrz.utils; + +import java.util.Map; + +/** + * Map 链式快速使用 + * @param + * @param + */ +public class MapChain { + private Map map; + + public MapChain(Map map) { + this.map = map; + } + + /** + * 可链式使用put + * 如 put(k,v).put(k,v).put(k,v).put(k,v).put(k,v).getMap() + * @param k + * @param v + * @return + */ + @SuppressWarnings("unchecked") + public MapChain put(Object k, Object v) { + map.put((K)k, (V)v); + return this; + } + + /** + * 快速获取当前map + * @return + */ + public Map getMap() { + return map; + } +} diff --git a/common/src/main/java/com/qmrz/utils/MapUtil.java b/common/src/main/java/com/qmrz/utils/MapUtil.java new file mode 100644 index 0000000..d72d1bb --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/MapUtil.java @@ -0,0 +1,50 @@ +package com.qmrz.utils; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class MapUtil { + /** + * 快速创建Map + * 转http提交的参数形式 + * + * @param map + * @return + */ + public static StringBuffer toParam(Map map) { + StringBuffer strParam = new StringBuffer(); + if (map == null) { + return strParam; + } + int i = 0; + for (String key : map.keySet()) { + i++; + if (i == 1) { + strParam.append(key + "=" + map.get(key)); + } else { + strParam.append("&" + key + "=" + map.get(key)); + } + } + return strParam; + } + + /** + * 快速创建map + * @return + */ + public static MapChain newMap() { + return new MapChain<>(new LinkedHashMap()); + } + + /** + * 快速创建map,并初始化 + * @param map + * @return + */ + public static MapChain newMap(Map map) { + if (map == null) { + return new MapChain<>(new LinkedHashMap()); + } + return new MapChain<>(map); + } +} diff --git a/common/src/main/java/com/qmrz/utils/MetaspaceEmptyCapacityExpansion.java b/common/src/main/java/com/qmrz/utils/MetaspaceEmptyCapacityExpansion.java new file mode 100644 index 0000000..c872de0 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/MetaspaceEmptyCapacityExpansion.java @@ -0,0 +1,11 @@ +package com.qmrz.utils; + +/** + * metaspace手动时扩容专用 + */ +public class MetaspaceEmptyCapacityExpansion { + + public void test(){ + + } +} diff --git a/common/src/main/java/com/qmrz/utils/MoneyUtil.java b/common/src/main/java/com/qmrz/utils/MoneyUtil.java new file mode 100644 index 0000000..c8a9008 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/MoneyUtil.java @@ -0,0 +1,38 @@ +package com.qmrz.utils; + +import java.math.BigDecimal; + +public class MoneyUtil { + /** + * 解析金额 + * 1、金额保留两位小数点后 + * 2、单元转分 + * @param payMoney + * @return 返回分的无符号长整数类型 + */ + public static Long parsePayMoney(BigDecimal payMoney){ + float tmpMoney = payMoney.floatValue(); + //保留两位小数后去除小数点 + String strMoney = String.format("%.2f", tmpMoney).replace(".", ""); + return Long.parseUnsignedLong(strMoney); + } + + /** + * 分转元 + * @param payMoney + * @return + */ + public static BigDecimal parseFenToYuan(Long payMoney){ + return new BigDecimal(payMoney).divide(new BigDecimal(100)); + } + + /** + * 转成标准金额,保留两位小数 + * @param payMoney + * @return + */ + public static BigDecimal parseStandardPay(BigDecimal payMoney){ + String strMoney = String.format("%.2f", payMoney.floatValue()); + return new BigDecimal(strMoney); + } +} diff --git a/common/src/main/java/com/qmrz/utils/PackageUtil.java b/common/src/main/java/com/qmrz/utils/PackageUtil.java new file mode 100644 index 0000000..f29795d --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/PackageUtil.java @@ -0,0 +1,142 @@ +package com.qmrz.utils; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +public class PackageUtil { + /** + * 获取某包下(包括该包的所有子包)所有类 + * @param packageName 包名 + * @return 类的完整名称 + */ +// public static List getClassName(String packageName) { +// return getClassName(packageName, true); +// } + + /** + * 获取某包下所有类 + * @param packageName 包名 + * @param childPackage 是否遍历子包 + * @return 类的完整名称 + */ + public static List getClassName(String packageName, boolean childPackage) { + List fileNames = null; + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + String packagePath = packageName.replace(".", "/"); + URL url = loader.getResource(packagePath); + if (url != null) { + String type = url.getProtocol(); + if (type.equals("file")) { + fileNames = getClassNameByFile(url.getPath(), null, childPackage); + } else if (type.equals("jar")) { + fileNames = getClassNameByJar(url.getPath(), childPackage); + } + } else { + fileNames = getClassNameByJars(((URLClassLoader) loader).getURLs(), packagePath, childPackage); + } + return fileNames; + } + + /** + * 从项目文件获取某包下所有类 + * @param filePath 文件路径 + * @param className 类名集合 + * @param childPackage 是否遍历子包 + * @return 类的完整名称 + */ + private static List getClassNameByFile(String filePath, List className, boolean childPackage) { + List myClassName = new ArrayList(); + File file = new File(filePath); + File[] childFiles = file.listFiles(); + for (File childFile : childFiles) { + if (childFile.isDirectory()) { + if (childPackage) { + myClassName.addAll(getClassNameByFile(childFile.getPath(), myClassName, childPackage)); + } + } else { + String childFilePath = childFile.getPath(); + if (childFilePath.endsWith(".class")) { + childFilePath = childFilePath.substring(childFilePath.indexOf("\\classes") + 9, childFilePath.lastIndexOf(".")); + childFilePath = childFilePath.replace("\\", "."); + myClassName.add(childFilePath); + } + } + } + + return myClassName; + } + + /** + * 从jar获取某包下所有类 + * @param jarPath jar文件路径 + * @param childPackage 是否遍历子包 + * @return 类的完整名称 + */ + private static List getClassNameByJar(String jarPath, boolean childPackage) { + List myClassName = new ArrayList(); + String[] jarInfo = jarPath.split("!"); + String jarFilePath = jarInfo[0].substring(jarInfo[0].indexOf("/")); + String packagePath = jarInfo[1].substring(1); + try { + JarFile jarFile = new JarFile(jarFilePath); + Enumeration entrys = jarFile.entries(); + while (entrys.hasMoreElements()) { + JarEntry jarEntry = entrys.nextElement(); + String entryName = jarEntry.getName(); + if (entryName.endsWith(".class")) { + if (childPackage) { + if (entryName.startsWith(packagePath)) { + entryName = entryName.replace("/", ".").substring(0, entryName.lastIndexOf(".")); + myClassName.add(entryName); + } + } else { + int index = entryName.lastIndexOf("/"); + String myPackagePath; + if (index != -1) { + myPackagePath = entryName.substring(0, index); + } else { + myPackagePath = entryName; + } + if (myPackagePath.equals(packagePath)) { + entryName = entryName.replace("/", ".").substring(0, entryName.lastIndexOf(".")); + myClassName.add(entryName); + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return myClassName; + } + + /** + * 从所有jar中搜索该包,并获取该包下所有类 + * @param urls URL集合 + * @param packagePath 包路径 + * @param childPackage 是否遍历子包 + * @return 类的完整名称 + */ + private static List getClassNameByJars(URL[] urls, String packagePath, boolean childPackage) { + List myClassName = new ArrayList(); + if (urls != null) { + for (int i = 0; i < urls.length; i++) { + URL url = urls[i]; + String urlPath = url.getPath(); + // 不必搜索classes文件夹 + if (urlPath.endsWith("classes/")) { + continue; + } + String jarPath = urlPath + "!/" + packagePath; + myClassName.addAll(getClassNameByJar(jarPath, childPackage)); + } + } + return myClassName; + } +} diff --git a/common/src/main/java/com/qmrz/utils/PageData.java b/common/src/main/java/com/qmrz/utils/PageData.java new file mode 100644 index 0000000..52666e4 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/PageData.java @@ -0,0 +1,49 @@ +package com.qmrz.utils; + +import com.github.pagehelper.Page; + +import java.util.List; + +public class PageData { + private Page data; + private int pageIndex; + private int pageSize; + private int pageCount; + private long rowCount; + + public PageData(List page) { + this.data = (Page) page; + this.pageIndex = data.getPageNum(); + this.pageSize = data.getPageSize(); + this.pageCount = data.getPages(); + this.rowCount = data.getTotal(); + } + + public static PageData newobj(Page page) { + return new PageData(page); + } + + public static PageData newobj(List page) { + return new PageData(page); + } + + public int getPageIndex() { + return this.pageIndex; + } + + public int getPageSize() { + return this.pageSize; + } + + public int getPageCount() { + return this.pageCount; + } + + public long getRowCount() { + return this.rowCount; + } + + public Page getData() { + return data; + } +} diff --git a/common/src/main/java/com/qmrz/utils/ParamUtil.java b/common/src/main/java/com/qmrz/utils/ParamUtil.java new file mode 100644 index 0000000..ace5a63 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/ParamUtil.java @@ -0,0 +1,5 @@ +package com.qmrz.utils; + +public class ParamUtil { + +} diff --git a/common/src/main/java/com/qmrz/utils/RD.java b/common/src/main/java/com/qmrz/utils/RD.java new file mode 100644 index 0000000..9322ddf --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/RD.java @@ -0,0 +1,119 @@ +package com.qmrz.utils; + +import lombok.ToString; + +/** + * 统一数据响应格式 + * json格式:{"status":10200,"msg":"success","data":任何数据} + */ +@ToString +public class RD { + private int status; + private String msg; + private Object data; + + public RD(RDCode status, String msg, Object data) { + this.status = status.getState(); + this.msg = msg; + this.data = data; + } + + public static RD create(RDCode state, String msg, Object data) { + return new RD(state, msg, data); + } + + public static RD create(RDCode state,Object data) { + return new RD(state, state.getMessage(), data); + } + + public static RD create(RDCode state) { + return new RD(state, state.getMessage(), ""); + } + + public static RD notfound() { + return create(RDCode.notfound, ""); + } + + public static RD notlogin() { + return create(RDCode.notlogin, ""); + } + + public static RD usernotlogin(){ + return create(RDCode.usernotlogin, ""); + } + + public static RD exception(String msg) { + return create(RDCode.exception, msg, ""); + } + + public static RD notpermission() { + return create(RDCode.nopermission, ""); + } + + //失败 + public static RD failure() { + return create(RDCode.failure, ""); + } + + public static RD failure(String msg) { + return create(RDCode.failure, msg, ""); + } + + public static RD failure(String msg, Object data) { + return create(RDCode.failure, msg, data); + } + + public static RD failureByForm(String msg, Object data) { + return create(RDCode.failureByForm, msg, data); + } + + //成功 + public static RD success() { + return create(RDCode.success, ""); + } + + public static RD success(Object data) { + return create(RDCode.success, data); + } + + public static RD success(String msg, Object data) { + return create(RDCode.success, msg, data); + } + + //快速 + public static RD quick(boolean b) { + if (b) { + return success(); + } else { + return failure(); + } + } + + /** + * 成功:返回数据,失败:返回失败信息 + * + * @param b + * @param failureMsg 失败时返回失败信息 + * @param successdata 成功时返回数据 + * @return + */ + public static RD quick(boolean b, String failureMsg, Object successdata) { + if (b) { + return success(successdata); + } else { + return failure(failureMsg); + } + } + + public int getStatus() { + return status; + } + + public String getMsg() { + return msg; + } + + public Object getData() { + return data; + } +} diff --git a/common/src/main/java/com/qmrz/utils/RDCode.java b/common/src/main/java/com/qmrz/utils/RDCode.java new file mode 100644 index 0000000..fa9beb4 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/RDCode.java @@ -0,0 +1,45 @@ +package com.qmrz.utils; + +/** + * 统一数据响应状态值 + * 10200 成功 + * 10555 失败 + * 10556 失败,并返回具体错误信息(主要用于后台表单验证时一次性输出失败原因) + * 10404 找不到地址 + * 10500 服务端异常 + * 10401 管理员未登录或超时 + * 10402 用户未登录或超时 + */ +public enum RDCode { + success(10200, "success"), + failure(10555, "failure"), + failureByForm(10556, "failureByForm"), + notfound(10404, "请求地址不存在"), + exception(10500, "服务端异常"), + nopermission(10403, "无访问权限"), + notlogin(10401, "未登录或超时"), + usernotlogin(10402, "用户未登录或超时"), + subuserlimit(10405, "子帐号不超过3个"), + userexist(10406,"用户已存在"), + nobindphone(10407,"未绑定手机号码"), + notauthorization(10408, "用户未授权或超时"), + exception_dida(20500, "迪达接口异常"), + notqrcode(20409, "没有扫二维码"), + exception_equip(30500, "设备接口异常"); + + private int state = 0; + private String message = ""; + + private RDCode(int value, String message) { + this.state = value; + this.message = message; + } + + public int getState() { + return state; + } + + public String getMessage() { + return message; + } +} diff --git a/common/src/main/java/com/qmrz/utils/ReStreamInput.java b/common/src/main/java/com/qmrz/utils/ReStreamInput.java new file mode 100644 index 0000000..cf2b68c --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/ReStreamInput.java @@ -0,0 +1,26 @@ +package com.qmrz.utils; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * 支持InputStream可重复读 + */ +public class ReStreamInput { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + public ReStreamInput(InputStream inputStream) throws IOException { + byte[] buffer = new byte[1024]; + int len; + while ((len = inputStream.read(buffer)) > -1) { + byteArrayOutputStream.write(buffer, 0, len); + } + byteArrayOutputStream.flush(); + } + + public InputStream getInputStream(){ + return new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); + } +} diff --git a/common/src/main/java/com/qmrz/utils/Session.java b/common/src/main/java/com/qmrz/utils/Session.java new file mode 100644 index 0000000..0352d5e --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/Session.java @@ -0,0 +1,22 @@ +package com.qmrz.utils; + +import javax.servlet.http.HttpSession; + +public class Session { + public static void removeSession(String key){ + getSession().removeAttribute(key); + } + + public static void setSession(String key,Object val){ + getSession().setAttribute(key, val); + } + + @SuppressWarnings("unchecked") + public static T getSession(String key) { + return (T) getSession().getAttribute(key); + } + + public static HttpSession getSession() { + return Web.getRequest().getSession(); + } +} diff --git a/common/src/main/java/com/qmrz/utils/SpringContextUtil.java b/common/src/main/java/com/qmrz/utils/SpringContextUtil.java new file mode 100644 index 0000000..74810c4 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/SpringContextUtil.java @@ -0,0 +1,37 @@ +package com.qmrz.utils; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +@Component +public class SpringContextUtil implements ApplicationContextAware { + private static ApplicationContext ac; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + ac = applicationContext; + } + + /** + * 通过name获取 Bean. + * + * @param name + * @return + */ + public static Object getBean(String name) { + return ac.getBean(name); + } + + /** + * 通过class获取Bean. + * + * @param clazz + * @param + * @return + */ + public static T getBean(Class clazz) { + return ac.getBean(clazz); + } +} diff --git a/common/src/main/java/com/qmrz/utils/StreamUtil.java b/common/src/main/java/com/qmrz/utils/StreamUtil.java new file mode 100644 index 0000000..2cba79c --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/StreamUtil.java @@ -0,0 +1,35 @@ +package com.qmrz.utils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +public class StreamUtil { + public static StringBuffer inputToString(InputStream inputStream) { + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + StringBuffer sb = new StringBuffer(); + String tmp = null; + + try { + while (true) { + tmp = reader.readLine(); + if (tmp == null) { + break; + } + sb.append(tmp); + } + } catch (IOException e) { + e.printStackTrace(); + }finally { + try { + reader.close(); + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + return sb; + } +} diff --git a/common/src/main/java/com/qmrz/utils/ValidateUtil.java b/common/src/main/java/com/qmrz/utils/ValidateUtil.java new file mode 100644 index 0000000..d8db045 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/ValidateUtil.java @@ -0,0 +1,6 @@ +package com.qmrz.utils; + +public class ValidateUtil { + + +} diff --git a/common/src/main/java/com/qmrz/utils/VerifyCodeUtil.java b/common/src/main/java/com/qmrz/utils/VerifyCodeUtil.java new file mode 100644 index 0000000..95b30a2 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/VerifyCodeUtil.java @@ -0,0 +1,299 @@ +package com.qmrz.utils; + +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletResponse; +import java.awt.*; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.Random; + +public class VerifyCodeUtil { + //使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符 + public static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ"; + private static Random random = new Random(); + + public static void renderCode(String verifyCodeName, String customerDir, int num) throws IOException { + HttpServletResponse response = Web.getResponse(); + response.setHeader("Pragma", "No-cache"); + response.setHeader("Cache-Control", "no-cache"); + response.setDateHeader("Expires", 0); + response.setContentType("image/jpeg"); + + // 生成随机字串 + String verifyCode = VerifyCodeUtil.generateVerifyCode(num); + + String name = "verifycode:" + verifyCodeName + ":" + customerDir;//验证码名称 + + Session.setSession(name, verifyCode); + + // 存入会话session + //HttpSession session = request.getSession(true); + // 删除以前的 +// session.removeAttribute("verCode"); +// session.removeAttribute("codeTime"); +// session.setAttribute("verCode", verifyCode.toLowerCase()); +// session.setAttribute("codeTime", LocalDateTime.now()); + // 生成图片 + int w = 100, h = 32; + VerifyCodeUtil.outputImage(w, h, response.getOutputStream(), verifyCode); + } + + public static boolean checkCode(String verifyCodeName, String customerDir, String code) { + String name = "verifycode:" + verifyCodeName + ":" + customerDir;//验证码名称 + String val = Session.getSession(name); + if (val == null) { + return false; + } + val = val.toLowerCase(); + boolean b = code.toLowerCase().equals(val); + Session.removeSession(name); + return b; + } + + /** + * 使用系统默认字符源生成验证码 + * + * @param verifySize 验证码长度 + * @return + */ + public static String generateVerifyCode(int verifySize) { + return generateVerifyCode(verifySize, VERIFY_CODES); + } + + /** + * 使用指定源生成验证码 + * + * @param verifySize 验证码长度 + * @param sources 验证码字符源 + * @return + */ + public static String generateVerifyCode(int verifySize, String sources) { + if (sources == null || sources.length() == 0) { + sources = VERIFY_CODES; + } + int codesLen = sources.length(); + Random rand = new Random(System.currentTimeMillis()); + StringBuilder verifyCode = new StringBuilder(verifySize); + for (int i = 0; i < verifySize; i++) { + verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1))); + } + return verifyCode.toString(); + } + + /** + * 生成随机验证码文件,并返回验证码值 + * + * @param w + * @param h + * @param outputFile + * @param verifySize + * @return + * @throws IOException + */ + public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException { + String verifyCode = generateVerifyCode(verifySize); + outputImage(w, h, outputFile, verifyCode); + return verifyCode; + } + + /** + * 输出随机验证码图片流,并返回验证码值 + * + * @param w + * @param h + * @param os + * @param verifySize + * @return + * @throws IOException + */ + public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException { + String verifyCode = generateVerifyCode(verifySize); + outputImage(w, h, os, verifyCode); + return verifyCode; + } + + /** + * 生成指定验证码图像文件 + * + * @param w + * @param h + * @param outputFile + * @param code + * @throws IOException + */ + public static void outputImage(int w, int h, File outputFile, String code) throws IOException { + if (outputFile == null) { + return; + } + File dir = outputFile.getParentFile(); + if (!dir.exists()) { + dir.mkdirs(); + } + try { + outputFile.createNewFile(); + FileOutputStream fos = new FileOutputStream(outputFile); + outputImage(w, h, fos, code); + fos.close(); + } catch (IOException e) { + throw e; + } + } + + /** + * 输出指定验证码图片流 + * + * @param w + * @param h + * @param os + * @param code + * @throws IOException + */ + public static void outputImage(int w, int h, OutputStream os, String code) throws IOException { + int verifySize = code.length(); + BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + Random rand = new Random(); + Graphics2D g2 = image.createGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + Color[] colors = new Color[5]; + Color[] colorSpaces = new Color[]{Color.WHITE, Color.CYAN, + Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, + Color.PINK, Color.YELLOW}; + float[] fractions = new float[colors.length]; + for (int i = 0; i < colors.length; i++) { + colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)]; + fractions[i] = rand.nextFloat(); + } + Arrays.sort(fractions); + + g2.setColor(Color.GRAY);// 设置边框色 + g2.fillRect(0, 0, w, h); + + Color c = getRandColor(200, 250); + g2.setColor(c);// 设置背景色 + g2.fillRect(0, 2, w, h - 4); + + //绘制干扰线 + Random random = new Random(); + g2.setColor(getRandColor(160, 200));// 设置线条的颜色 + for (int i = 0; i < 20; i++) { + int x = random.nextInt(w - 1); + int y = random.nextInt(h - 1); + int xl = random.nextInt(6) + 1; + int yl = random.nextInt(12) + 1; + g2.drawLine(x, y, x + xl + 40, y + yl + 20); + } + + // 添加噪点 + float yawpRate = 0.05f;// 噪声率 + int area = (int) (yawpRate * w * h); + for (int i = 0; i < area; i++) { + int x = random.nextInt(w); + int y = random.nextInt(h); + int rgb = getRandomIntColor(); + image.setRGB(x, y, rgb); + } + + shear(g2, w, h, c);// 使图片扭曲 + + g2.setColor(getRandColor(100, 160)); + int fontSize = h - 4; + Font font = new Font("Algerian", Font.ITALIC, fontSize); + g2.setFont(font); + char[] chars = code.toCharArray(); + for (int i = 0; i < verifySize; i++) { + AffineTransform affine = new AffineTransform(); + affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize / 2, h / 2); + g2.setTransform(affine); + g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10); + } + + g2.dispose(); + ImageIO.write(image, "jpg", os); + } + + private static Color getRandColor(int fc, int bc) { + if (fc > 255) + fc = 255; + if (bc > 255) + bc = 255; + int r = fc + random.nextInt(bc - fc); + int g = fc + random.nextInt(bc - fc); + int b = fc + random.nextInt(bc - fc); + return new Color(r, g, b); + } + + private static int getRandomIntColor() { + int[] rgb = getRandomRgb(); + int color = 0; + for (int c : rgb) { + color = color << 8; + color = color | c; + } + return color; + } + + private static int[] getRandomRgb() { + int[] rgb = new int[3]; + for (int i = 0; i < 3; i++) { + rgb[i] = random.nextInt(255); + } + return rgb; + } + + private static void shear(Graphics g, int w1, int h1, Color color) { + shearX(g, w1, h1, color); + shearY(g, w1, h1, color); + } + + private static void shearX(Graphics g, int w1, int h1, Color color) { + + int period = random.nextInt(2); + + boolean borderGap = true; + int frames = 1; + int phase = random.nextInt(2); + + for (int i = 0; i < h1; i++) { + double d = (double) (period >> 1) + * Math.sin((double) i / (double) period + + (6.2831853071795862D * (double) phase) + / (double) frames); + g.copyArea(0, i, w1, 1, (int) d, 0); + if (borderGap) { + g.setColor(color); + g.drawLine((int) d, i, 0, i); + g.drawLine((int) d + w1, i, w1, i); + } + } + + } + + private static void shearY(Graphics g, int w1, int h1, Color color) { + + int period = random.nextInt(40) + 10; // 50; + + boolean borderGap = true; + int frames = 20; + int phase = 7; + for (int i = 0; i < w1; i++) { + double d = (double) (period >> 1) + * Math.sin((double) i / (double) period + + (6.2831853071795862D * (double) phase) + / (double) frames); + g.copyArea(i, 0, 1, h1, 0, (int) d); + if (borderGap) { + g.setColor(color); + g.drawLine(i, (int) d, i, 0); + g.drawLine(i, (int) d + h1, i, h1); + } + + } + + } +} + diff --git a/common/src/main/java/com/qmrz/utils/Web.java b/common/src/main/java/com/qmrz/utils/Web.java new file mode 100644 index 0000000..d7b42fd --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/Web.java @@ -0,0 +1,215 @@ +package com.qmrz.utils; + +import com.qmrz.exception.ABException; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.imageio.ImageIO; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.*; +import java.util.Calendar; + +@Slf4j +public class Web { + public static void redirect(String path) throws IOException { + getResponse().sendRedirect(path); + } + + public static void setNoCache() { + getResponse().addHeader("Cache-Control", "no-cache"); + } + + public static void setCache() { + HttpServletResponse response = getResponse(); + response.setHeader("Cache-Control", "max-age=315360000"); + + Calendar now = Calendar.getInstance(); + now.add(Calendar.YEAR, 10); + response.setHeader("Expires", DateTimeUtil.formatGMTBySecond(now.getTimeInMillis() / 1000L)); + } + + public static HttpServletResponse getResponse() { + return getRequestAttributes().getResponse(); + } + + public static HttpServletRequest getRequest() { + return getRequestAttributes().getRequest(); + } + + public static ServletRequestAttributes getRequestAttributes() { + return (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + } + + public static String getRequestBody() { + String line = ""; + String result = null; + HttpServletRequest request = Web.getRequest(); + try { + BufferedReader reader = request.getReader(); + StringBuffer inputString = new StringBuffer(); + while ((line = reader.readLine()) != null) { + inputString.append(line); + } + result = inputString.toString(); + request.getReader().close(); + } catch (IOException e) { + String msg = "获取请求内容时异常:" + e.getMessage(); + log.info(msg); + throw new ABException(msg); + } + return result; + } + + public static void printRD(ServletResponse response, RD rd) { + //response.setHeader("Cache-Control","no-cache"); + response.setContentType("application/json;charset=UTF-8"); + + try { + response.getWriter().print(JSONObject.toJSONString(rd)); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void responseImage(String fileName) { + Web.getResponse().setContentType("image/jpeg"); + + File file = new File(fileName); + + FileInputStream inputStream = null; + try { + inputStream = new FileInputStream(file); + byte[] data = new byte[(int) file.length()]; + int length = inputStream.read(data); + inputStream.close(); + OutputStream stream = Web.getResponse().getOutputStream(); + stream.write(data); + stream.flush(); + stream.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * InputStream转数组 + * @param input + * @return + * @throws IOException + */ + private static byte[] toByteArray(InputStream input) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + byte[] buffer = new byte[4096]; + int n = 0; + while (-1 != (n = input.read(buffer))) { + output.write(buffer, 0, n); + } + return output.toByteArray(); + } + + /** + * 响应InputStream + * @param inputStream + */ + public static void responseInputStream(InputStream inputStream) { + try { + byte[] data = toByteArray(inputStream); + inputStream.close(); + OutputStream stream = Web.getResponse().getOutputStream(); + stream.write(data); + stream.flush(); + stream.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void responseImage2(String fileName) { + HttpServletResponse response = Web.getResponse(); + response.setContentType("image/jpeg"); + response.setHeader("Cache-Control", "max-age=315360000"); + + Calendar now = Calendar.getInstance(); + now.add(Calendar.YEAR, 10); + response.setHeader("Expires", DateTimeUtil.formatGMTBySecond(now.getTimeInMillis() / 1000L)); + +// response.setHeader("Accept-Ranges", "bytes"); + Image image2 = Toolkit.getDefaultToolkit().getImage(fileName); + log.info(fileName); + try { + BufferedImage image3 = ImageUtil.toBufferedImage(image2); + ImageIO.write(image3, "jpg", Web.getResponse().getOutputStream()); + } catch (Exception e) { + log.error(e.getMessage()); + } + } + +// public static void responseImage2(InputStream inputStream,int streamLength) { +// HttpServletResponse response = Web.getResponse(); +// response.setContentType("image/jpeg"); +// response.setHeader("Cache-Control", "max-age=315360000"); +// +// Calendar now = Calendar.getInstance(); +// now.add(Calendar.YEAR, 10); +// response.setHeader("Expires", DateTimeUtil.formatGMTBySecond(now.getTimeInMillis() / 1000L)); +// +//// response.setHeader("Accept-Ranges", "bytes"); +// Image image2 = Toolkit.getDefaultToolkit().getImage(fileName); +// Toolkit.getDefaultToolkit().getImage() +// System.out.println(fileName); +// try { +// BufferedImage image3 = ImageUtil.toBufferedImage(image2); +// ImageIO.write(image3, "jpg", Web.getResponse().getOutputStream()); +// } catch (Exception e) { +// log.error(e.getMessage()); +// } +// } + + public static void responseText(String content) { + if (content == null) { + content = ""; + } + Web.getResponse().setContentType("text/plain"); + PrintWriter writer = null; + try { + writer = Web.getResponse().getWriter(); + writer.write(content); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (writer != null) { + writer.flush(); + writer.close(); + } + } + } + + public static void responseText(String content, String contentType) { + if (content == null) { + content = ""; + } + Web.getResponse().setContentType(contentType); + PrintWriter writer = null; + try { + writer = Web.getResponse().getWriter(); + writer.write(content); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (writer != null) { + writer.flush(); + writer.close(); + } + } + } +} diff --git a/common/src/main/java/com/qmrz/utils/XMLUtil.java b/common/src/main/java/com/qmrz/utils/XMLUtil.java new file mode 100644 index 0000000..7bb2ae0 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/XMLUtil.java @@ -0,0 +1,113 @@ +package com.qmrz.utils; + +import lombok.extern.slf4j.Slf4j; +import org.dom4j.DocumentHelper; +import org.dom4j.Element; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +public class XMLUtil { + /** + * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。 + * 解决:2字节的UTF-8序列的字节2无效的错误 + * @param strxml + * @return + * @throws Exception + * @throws IOException + */ + public static Map doXMLParseByDom4j(String strxml) throws Exception { + Map map = new HashMap(); + org.dom4j.Document doc = null; + try { + // 将字符串转为XML + doc = DocumentHelper.parseText(strxml); + // 获取根节点 + org.dom4j.Element rootElt = doc.getRootElement(); + // 拿到根节点的名称 + log.info("根节点:" + rootElt.getName()); + + List iList = rootElt.elements(); + + for(int i=0;i data) throws Exception { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder(); + org.w3c.dom.Document document = documentBuilder.newDocument(); + org.w3c.dom.Element root = document.createElement("xml"); + document.appendChild(root); + for (String key: data.keySet()) { + String value = data.get(key); + if (value == null) { + value = ""; + } + value = value.trim(); + org.w3c.dom.Element filed = document.createElement(key); + filed.appendChild(document.createTextNode(value)); + root.appendChild(filed); + } + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer = tf.newTransformer(); + DOMSource source = new DOMSource(document); + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + StringWriter writer = new StringWriter(); + StreamResult result = new StreamResult(writer); + transformer.transform(source, result); + String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", ""); + try { + writer.close(); + } + catch (Exception ex) { + } + return output; + } +} diff --git a/common/src/main/java/com/qmrz/utils/classload/JavaStringCompiler.java b/common/src/main/java/com/qmrz/utils/classload/JavaStringCompiler.java new file mode 100644 index 0000000..0717fd7 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/classload/JavaStringCompiler.java @@ -0,0 +1,71 @@ +package com.qmrz.utils.classload; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; + +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; +import javax.tools.JavaCompiler.CompilationTask; + +/** + * In-memory compile Java source code as String. + * + * @author michael + */ +public class JavaStringCompiler { + + JavaCompiler compiler; + StandardJavaFileManager stdManager; + + public JavaStringCompiler() { + this.compiler = ToolProvider.getSystemJavaCompiler(); + this.stdManager = compiler.getStandardFileManager(null, null, null); + } + + /** + * Compile a Java source file in memory. + * + * @param fileName + * Java file name, e.g. "Test.java" + * @param source + * The source code as String. + * @return The compiled results as Map that contains class name as key, + * class binary as value. + * @throws IOException + * If compile error. + */ + public Map compile(String fileName, String source) throws IOException { + try (MemoryJavaFileManager manager = new MemoryJavaFileManager(stdManager)) { + JavaFileObject javaFileObject = manager.makeStringSource(fileName, source); + CompilationTask task = compiler.getTask(null, manager, null, null, null, Arrays.asList(javaFileObject)); + + Boolean result = task.call(); + if (result == null || !result.booleanValue()) { + throw new RuntimeException("Compilation failed."); + } + return manager.getClassBytes(); + } + } + + /** + * Load class from compiled classes. + * + * @param name + * Full class name. + * @param classBytes + * Compiled results as a Map. + * @return The Class instance. + * @throws ClassNotFoundException + * If class not found. + * @throws IOException + * If load error. + */ + public Class loadClass(String name, Map classBytes) throws ClassNotFoundException, IOException { + try (MemoryClassLoader classLoader = new MemoryClassLoader(classBytes)) { + return classLoader.loadClass(name); + } + } +} \ No newline at end of file diff --git a/common/src/main/java/com/qmrz/utils/classload/MemoryClassLoader.java b/common/src/main/java/com/qmrz/utils/classload/MemoryClassLoader.java new file mode 100644 index 0000000..2d464d1 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/classload/MemoryClassLoader.java @@ -0,0 +1,32 @@ +package com.qmrz.utils.classload; + +import java.net.URL; +import java.net.URLClassLoader; +import java.util.HashMap; +import java.util.Map; + +/** + * class加载到内存 + */ +public class MemoryClassLoader extends URLClassLoader { + + // class name to class bytes: + Map classBytes = new HashMap<>(); + + public MemoryClassLoader(Map classBytes) { + super(new URL[0], MemoryClassLoader.class.getClassLoader()); + this.classBytes.putAll(classBytes); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + byte[] buf = classBytes.get(name); + if (buf == null) { + return super.findClass(name); + } + classBytes.remove(name); + + return defineClass(name, buf, 0, buf.length); + } + +} \ No newline at end of file diff --git a/common/src/main/java/com/qmrz/utils/classload/MemoryJavaFileManager.java b/common/src/main/java/com/qmrz/utils/classload/MemoryJavaFileManager.java new file mode 100644 index 0000000..ca2f43a --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/classload/MemoryJavaFileManager.java @@ -0,0 +1,84 @@ +package com.qmrz.utils.classload; + +import javax.tools.*; +import java.io.ByteArrayOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.nio.CharBuffer; +import java.util.HashMap; +import java.util.Map; + +public class MemoryJavaFileManager extends ForwardingJavaFileManager { + // compiled classes in bytes: + final Map classBytes = new HashMap<>(); + + MemoryJavaFileManager(JavaFileManager fileManager) { + super(fileManager); + } + + public Map getClassBytes() { + return new HashMap(this.classBytes); + } + + @Override + public void flush() throws IOException { + } + + @Override + public void close() throws IOException { + classBytes.clear(); + } + + @Override + public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, JavaFileObject.Kind kind, + FileObject sibling) throws IOException { + if (kind == JavaFileObject.Kind.CLASS) { + return new MemoryOutputJavaFileObject(className); + } else { + return super.getJavaFileForOutput(location, className, kind, sibling); + } + } + + JavaFileObject makeStringSource(String name, String code) { + return new MemoryInputJavaFileObject(name, code); + } + + static class MemoryInputJavaFileObject extends SimpleJavaFileObject { + + final String code; + + MemoryInputJavaFileObject(String name, String code) { + super(URI.create("string:///" + name), Kind.SOURCE); + this.code = code; + } + + @Override + public CharBuffer getCharContent(boolean ignoreEncodingErrors) { + return CharBuffer.wrap(code); + } + } + + class MemoryOutputJavaFileObject extends SimpleJavaFileObject { + final String name; + + MemoryOutputJavaFileObject(String name) { + super(URI.create("string:///" + name), Kind.CLASS); + this.name = name; + } + + @Override + public OutputStream openOutputStream() { + return new FilterOutputStream(new ByteArrayOutputStream()) { + @Override + public void close() throws IOException { + out.close(); + ByteArrayOutputStream bos = (ByteArrayOutputStream) out; + classBytes.put(name, bos.toByteArray()); + } + }; + } + + } +} diff --git a/common/src/main/java/com/qmrz/utils/coordinate/Angle.java b/common/src/main/java/com/qmrz/utils/coordinate/Angle.java new file mode 100644 index 0000000..c236d26 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/coordinate/Angle.java @@ -0,0 +1,89 @@ +package com.qmrz.utils.coordinate; + +import com.qmrz.exception.FailureException; +import com.qmrz.utils.Fn; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.math.BigDecimal; + +/** + * + */ +@Slf4j +@Data +public class Angle { + private double degree; + private double minute; + private double second; + + public double toDouble() { + double d = degree + minute / 60 + second / 3600; + BigDecimal b = new BigDecimal(d); + return b.setScale(6, BigDecimal.ROUND_HALF_UP).doubleValue(); + } + + public static Angle parse(String s) { + Angle angle = new Angle(); + char[] chars = s.toCharArray(); + String num = ""; + for (char ch : chars) { + if (Character.isDigit(ch)) { + num += ch; + } else if (ch == '度' || ch == '°') { + angle.setDegree(Integer.parseInt(num)); + num = ""; + } else if (ch == '分' || ch == '\'') { + angle.setMinute(Integer.parseInt(num)); + num = ""; + } else if (ch == '秒' || ch == '\"') { + angle.setSecond(Integer.parseInt(num)); + num = ""; + } else { + throw new FailureException("错误的格式。"); + } + } + + return angle; + } + + public static boolean check(String s) { + Angle angle = new Angle(); + char[] chars = s.toCharArray(); + String num = ""; + for (char ch : chars) { + if (Character.isDigit(ch)) { + num += ch; + } else if (ch == '度' || ch == '°') { + if (!Fn.isInt(num)) { + return false; + } + + num = ""; + } else if (ch == '分' || ch == '\'') { + if (!Fn.isInt(num)) { + return false; + } + num = ""; + } else if (ch == '秒' || ch == '\"') { + if (!Fn.isInt(num)) { + return false; + } + num = ""; + } else { + return false; + } + } + + return true; + } + + public static void main(String[] args) { + log.info(String.valueOf(check("13度23分89秒"))); + log.info(String.valueOf(check("13°23'89"))); + log.info(String.valueOf(Angle.parse("13度23分89秒"))); + Angle a = Angle.parse("13°23'89"); + log.info(String.valueOf(a)); + log.info(String.valueOf(a.toDouble())); + } +} diff --git a/common/src/main/java/com/qmrz/utils/coordinate/Gps.java b/common/src/main/java/com/qmrz/utils/coordinate/Gps.java new file mode 100644 index 0000000..cf33585 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/coordinate/Gps.java @@ -0,0 +1,20 @@ +package com.qmrz.utils.coordinate; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.ToString; + +@Data +@AllArgsConstructor +@ToString +public class Gps { + /** + * 经度 + */ + private double wgLon; + + /** + * 纬度 + */ + private double wgLat; +} diff --git a/common/src/main/java/com/qmrz/utils/coordinate/PositionUtil.java b/common/src/main/java/com/qmrz/utils/coordinate/PositionUtil.java new file mode 100644 index 0000000..def1aff --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/coordinate/PositionUtil.java @@ -0,0 +1,98 @@ +package com.qmrz.utils.coordinate; + +import lombok.extern.slf4j.Slf4j; + +/** + * 经纬度工具 + */ +@Slf4j +public class PositionUtil { + + private static final double EARTH_RADIUS = 6378.137;//6378.137,6371.393 + public static final double pi = Math.PI; + public static final double ee = 0.00669342162296594323; + public static final double a = 6378245.0; + + /** + * 地球坐标系 (WGS84) 与火星坐标系 (GCJ-02) 的转换算法 将 WGS84 坐标转换成 GCJ-02 坐标 + */ + public static Gps gps84_To_Gcj02(double lat, double lon) { + if (outOfChina(lat, lon)) { + return null; + } + double dLat = transformLat(lon - 105.0, lat - 35.0); + double dLon = transformLon(lon - 105.0, lat - 35.0); + double radLat = lat / 180.0 * pi; + double magic = Math.sin(radLat); + magic = 1 - ee * magic * magic; + double sqrtMagic = Math.sqrt(magic); + dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi); + dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi); + double mgLat = lat + dLat; + double mgLon = lon + dLon; + return new Gps(mgLat, mgLon); + } + + private static double transformLat(double x, double y) { + double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + + 0.2 * Math.sqrt(Math.abs(x)); + ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; + ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0; + ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0; + return ret; + } + + private static double transformLon(double x, double y) { + double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 + * Math.sqrt(Math.abs(x)); + ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; + ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0; + ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0; + return ret; + } + + public static boolean outOfChina(double lat, double lon) { + if (lon < 72.004 || lon > 137.8347) return true; + if (lat < 0.8293 || lat > 55.8271) return true; + return false; + } + + private static double rad(double d) { + return d * Math.PI / 180.0; + } + + /** + * 两点距离,单米 + * + * @param lat1 起点 纬度 + * @param lat2 终点 纬度 + * @param lng1 起点 经度 + * @param lng2 终点 经度 + * @return + */ + public static double getDistance(double lat1, double lng1, double lat2, + double lng2) { + double radLat1 = rad(lat1); + double radLat2 = rad(lat2); + double a = radLat1 - radLat2; + double b = rad(lng1) - rad(lng2); + double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + + Math.cos(radLat1) * Math.cos(radLat2) + * Math.pow(Math.sin(b / 2), 2))); + s = s * EARTH_RADIUS; + s = Math.round(s * 10000d) / 10000d; + s = s * 1000; + return s; + } + + public static void main(String[] args) { + log.info(String.valueOf(getDistance(30.331724, 120.086112, + 30.33099, 120.086228))); + + log.info(String.valueOf(getDistance(30.257325, 120.201425, + 29.303339, 120.092793))); + + log.info(String.valueOf(getDistance(30.302882, 120.084241, + 30.301108, 120.084220))); + } +} diff --git a/common/src/main/java/com/qmrz/utils/enumutil/EnumUtil.java b/common/src/main/java/com/qmrz/utils/enumutil/EnumUtil.java new file mode 100644 index 0000000..833ab2f --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/enumutil/EnumUtil.java @@ -0,0 +1,60 @@ +package com.qmrz.utils.enumutil; + +import com.qmrz.utils.MapUtil; +import org.apache.commons.collections.keyvalue.DefaultMapEntry; + +import java.util.*; + +/** + * 枚举工具 + */ +public class EnumUtil { + + /** + * 根据key获取枚举项 + * @param enumList + * @param key + * @return + */ + public static IEmun getEnumByKey(IEmun[] enumList, int key) { + for (IEmun item : enumList) { + if (item.getKey() == key) { + return item; + } + } + return null; + } + + /** + * 将枚举按taxis从大到小排序 + * + * @param enumList 枚举 项数组 如:PoliceRoleType.values() + * @return + */ + public static List> sortByTaxis(IEmun[] enumList) { + Map map = new TreeMap<>(new MapKeyComparator()); + + for (IEmun s : enumList) { + map.put(s.getTaxis(), s); + } + + List> mapList = new ArrayList<>(); + for (Map.Entry entry : map.entrySet()) { + Map tmp = MapUtil.newMap().put("key", entry.getValue().getKey()) + .put("name", entry.getValue().getName()).getMap(); + mapList.add(tmp); + } + + return mapList; + } + + /** + * 比较器,从大到小 + */ + static class MapKeyComparator implements Comparator { + @Override + public int compare(Integer o1, Integer o2) { + return o2.compareTo(o1); + } + } +} diff --git a/common/src/main/java/com/qmrz/utils/enumutil/IEmun.java b/common/src/main/java/com/qmrz/utils/enumutil/IEmun.java new file mode 100644 index 0000000..b3d6e4b --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/enumutil/IEmun.java @@ -0,0 +1,16 @@ +package com.qmrz.utils.enumutil; + +/** + * 枚举基础接口 + */ +public interface IEmun { + int getKey(); + + String getName(); + + /** + * 排序 + * @return + */ + int getTaxis(); +} diff --git a/common/src/main/java/com/qmrz/utils/http/HttpMethod.java b/common/src/main/java/com/qmrz/utils/http/HttpMethod.java new file mode 100644 index 0000000..602e99b --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/http/HttpMethod.java @@ -0,0 +1,6 @@ +package com.qmrz.utils.http; + +public class HttpMethod { + public static final String POST = "POST"; + public static final String GET = "GET"; +} diff --git a/common/src/main/java/com/qmrz/utils/http/HttpResult.java b/common/src/main/java/com/qmrz/utils/http/HttpResult.java new file mode 100644 index 0000000..b5c86c3 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/http/HttpResult.java @@ -0,0 +1,20 @@ +package com.qmrz.utils.http; + +import lombok.*; + +import java.util.List; +import java.util.Map; + +@AllArgsConstructor +@NoArgsConstructor +@Data +@ToString +public class HttpResult { + private Integer responseStatus; + private String responseBody; + private String message; + /** + * 响应头 + */ + private Map> responseHeader; +} diff --git a/common/src/main/java/com/qmrz/utils/http/HttpUtil.java b/common/src/main/java/com/qmrz/utils/http/HttpUtil.java new file mode 100644 index 0000000..3827e71 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/http/HttpUtil.java @@ -0,0 +1,378 @@ +package com.qmrz.utils.http; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.qmrz.utils.Json; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.Header; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicHeader; + +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Slf4j +public class HttpUtil { + public static JSONObject httpsRequestJson(String requestUrl, String requestMethod, String outputStr) { + JSONObject jsonObject = null; + try { + TrustManager[] tm = {new MyTrustManager()}; + SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); + sslContext.init(null, tm, new java.security.SecureRandom()); + SSLSocketFactory ssf = sslContext.getSocketFactory(); + + URL url = new URL(requestUrl); + HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); + conn.setSSLSocketFactory(ssf); + + conn.setDoOutput(true); + conn.setDoInput(true); + conn.setUseCaches(false); + conn.setRequestMethod(requestMethod); + if (null != outputStr) { + OutputStream outputStream = conn.getOutputStream(); + outputStream.write(outputStr.getBytes("UTF-8")); + outputStream.close(); + } + InputStream inputStream = conn.getInputStream(); + InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8"); + BufferedReader bufferedReader = new BufferedReader(inputStreamReader); + String str = null; + StringBuffer buffer = new StringBuffer(); + while ((str = bufferedReader.readLine()) != null) { + buffer.append(str); + } + bufferedReader.close(); + inputStreamReader.close(); + inputStream.close(); + inputStream = null; + conn.disconnect(); + log.info(" -- url: " + requestUrl); +// log.info(" -- result: " + buffer.toString()); + jsonObject = JSONObject.parseObject(buffer.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + return jsonObject; + } + + public static Object httpRequestJson(String requestUrl, String requestMethod, String outputStr) { + int responseCode = 30500;//默认系统异常 + try { + URL url = new URL(requestUrl); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + + conn.setDoOutput(true); + conn.setDoInput(true); + conn.setUseCaches(false); + conn.setRequestMethod(requestMethod.toUpperCase()); + if (null != outputStr) { + OutputStream outputStream = conn.getOutputStream(); + outputStream.write(outputStr.getBytes("UTF-8")); + outputStream.close(); + } + + InputStream inputStream; + responseCode = conn.getResponseCode(); + if (responseCode >= 400) { + inputStream = conn.getErrorStream(); + } else { + inputStream = conn.getInputStream(); + } + + InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8"); + BufferedReader bufferedReader = new BufferedReader(inputStreamReader); + String str = null; + StringBuffer buffer = new StringBuffer(); + while ((str = bufferedReader.readLine()) != null) { + buffer.append(str); + } + bufferedReader.close(); + inputStreamReader.close(); + inputStream.close(); + inputStream = null; + conn.disconnect(); + log.info(" -- url: " + requestUrl); +// log.info(" -- result: " + buffer.toString()); + Object jsonObject = Json.parse(buffer.toString()); + return jsonObject; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public static String getRequestFullUri(HttpServletRequest request) { + String port = ""; + if (request.getServerPort() != 80) { + port = ":" + request.getServerPort(); + } + return request.getScheme() + "://" + request.getServerName() + port + request.getContextPath() + request.getServletPath(); + } + + public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) { + String retStr = ""; + try { + TrustManager[] tm = {new MyTrustManager()}; + SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); + sslContext.init(null, tm, new java.security.SecureRandom()); + SSLSocketFactory ssf = sslContext.getSocketFactory(); + + URL url = new URL(requestUrl); + HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); + conn.setSSLSocketFactory(ssf); + + conn.setDoOutput(true); + conn.setDoInput(true); + conn.setUseCaches(false); + conn.setRequestMethod(requestMethod); + if (null != outputStr) { + OutputStream outputStream = conn.getOutputStream(); + outputStream.write(outputStr.getBytes("UTF-8")); + outputStream.close(); + } + InputStream inputStream = conn.getInputStream(); + InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8"); + BufferedReader bufferedReader = new BufferedReader(inputStreamReader); + String str = null; + StringBuffer buffer = new StringBuffer(); + while ((str = bufferedReader.readLine()) != null) { + buffer.append(str); + } + bufferedReader.close(); + inputStreamReader.close(); + inputStream.close(); + conn.disconnect(); + log.info(" -- url: " + requestUrl); +// log.info(" -- result: " + buffer.toString()); + retStr = buffer.toString(); + } catch (Exception e) { + e.printStackTrace(); + } + return retStr; + } + + public static HttpResult httpsRequestMap(String requestUrl, String requestMethod, String outputStr + , Map header) { + int responseCode = 30500;//默认系统异常 + String body = ""; + String msg = ""; + Map> responseHeader = null; + +// Map responseResult = new HashMap<>(); + try { + TrustManager[] tm = {new MyTrustManager()}; + SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); + sslContext.init(null, tm, new java.security.SecureRandom()); + SSLSocketFactory ssf = sslContext.getSocketFactory(); + + URL url = new URL(requestUrl); + HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); + conn.setSSLSocketFactory(ssf); + + if (header != null) { + header.forEach((key, val) -> conn.addRequestProperty(key, val)); + } + + conn.setDoOutput(true); + conn.setDoInput(true); + conn.setUseCaches(false); + conn.setRequestMethod(requestMethod); + if (null != outputStr) { + OutputStream outputStream = conn.getOutputStream(); + outputStream.write(outputStr.getBytes("UTF-8")); + outputStream.close(); + } + + responseCode = conn.getResponseCode(); + responseHeader = conn.getHeaderFields(); + InputStream inputStream; + if (responseCode >= 400) { + inputStream = conn.getErrorStream(); + } else { + inputStream = conn.getInputStream(); + } + + if (inputStream != null) { + InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8"); + BufferedReader bufferedReader = new BufferedReader(inputStreamReader); + String str = null; + StringBuffer buffer = new StringBuffer(); + while ((str = bufferedReader.readLine()) != null) { + buffer.append(str); + } + body = buffer.toString(); + bufferedReader.close(); + inputStreamReader.close(); + inputStream.close(); + } + + conn.disconnect(); + + log.info(" -- url: " + requestUrl); +// log.info(" -- result: " + body); + } catch (Exception e) { + msg = e.getMessage(); + responseHeader.forEach((key, val) -> { + log.info(" --- " + key + " --- "); + val.forEach(item -> { + log.info(" ---- " + item); + }); + }); + e.printStackTrace(); + } + + return new HttpResult(responseCode, body, msg, responseHeader); + } + + public static HttpResult httpRequestMap(String requestUrl, String requestMethod, String outputStr, Map header) { + int responseCode = 30500;//默认系统异常 + String body = ""; + String msg = ""; + Map> responseHeader = null; + try { + URL url = new URL(requestUrl); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + + if (header != null) { + header.forEach((key, val) -> conn.addRequestProperty(key, val)); + } + conn.setDoOutput(true); + conn.setDoInput(true); + conn.setUseCaches(false); + conn.setRequestMethod(requestMethod.toUpperCase()); + + if (null != outputStr) { + OutputStream outputStream = conn.getOutputStream(); + outputStream.write(outputStr.getBytes("UTF-8")); + outputStream.close(); + } + + responseCode = conn.getResponseCode(); + responseHeader = conn.getHeaderFields(); + + InputStream inputStream; + if (responseCode >= 400) { + inputStream = conn.getErrorStream(); + } else { + inputStream = conn.getInputStream(); + } + + if (inputStream != null) { + InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8"); + BufferedReader bufferedReader = new BufferedReader(inputStreamReader); + String str = null; + StringBuffer buffer = new StringBuffer(); + while ((str = bufferedReader.readLine()) != null) { + buffer.append(str); + } + body = buffer.toString(); + bufferedReader.close(); + inputStreamReader.close(); + inputStream.close(); + } + + conn.disconnect(); + + log.info(" -- url: " + requestUrl); + log.info(" -- responseCode: " + responseCode); +// log.info(" -- responseBody: " + body); + } catch (Exception e) { + msg = e.getMessage(); + responseHeader.forEach((key, val) -> { + log.info(" ---head info: " + key + " --- "); + val.forEach(item -> { + log.info(" ---- " + item); + }); + }); + + e.printStackTrace(); + } + return new HttpResult(responseCode, body, msg, responseHeader); + } + + private static final long RETRY_SLEEP_TIME_MILLIS = 2000; + + public static CloseableHttpClient createHttpClient(Map header) { + int maxRetries = 3; + ArrayList

headers = new ArrayList<>(); + header.forEach((key, val) -> { + headers.add(new BasicHeader(key, val)); + }); + + HttpClientBuilder httpBuilder = HttpClients.custom() + .setDefaultHeaders(headers); +// .setRetryHandler((exception, executionCount, context) -> { +// boolean retry = true; +// +// Boolean b = (Boolean) context.getAttribute(ExecutionContext.HTTP_REQ_SENT); +// boolean sent = (b != null && b.booleanValue()); +// +// if (executionCount > maxRetries) { +// // Do not retry if over max retry count +// retry = false; +//// } else if (isInList(exceptionBlacklist, exception)) { +//// // immediately cancel retry if the error is blacklisted +//// retry = false; +//// } else if (isInList(exceptionWhitelist, exception)) { +// // immediately retry if error is whitelisted +// retry = true; +// } else if (!sent) { +// // for most other errors, retry only if request hasn't been fully +// // sent yet +// retry = true; +// } +// +// HttpClientContext clientContext = HttpClientContext.adapt(context); +// HttpRequest request = clientContext.getRequest(); +// HttpResponse response = clientContext.getResponse(); +// StatusLine statusLine = response.getStatusLine(); +// +// boolean unauthorized = false; +// if (statusLine != null && statusLine.getStatusCode() == 401) { +// unauthorized = true; +//// ServerCaller caller = (ServerCaller) context.getAttribute("FBoxServerCaller"); +// try { +// System.out.println("ServerCaller: try get another token for " + request.toString()); +//// caller.accessToken = caller.tokenManager.getOrUpdateToken(caller.accessToken); +// request.setHeader("Authorization", "Bearer " + accessToken); +// retry = true; +// } catch (Exception e) { +// e.printStackTrace(); +// retry = false; +// } +// } +// +// if (retry && !unauthorized) { +// try { +// Thread.sleep(RETRY_SLEEP_TIME_MILLIS); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// } else { +// exception.printStackTrace(); +// } +// return retry; +// }); +// if (proxy != null) +// httpBuilder = httpBuilder.setProxy(proxy); + + CloseableHttpClient http = httpBuilder.build(); + return http; + } + +} diff --git a/common/src/main/java/com/qmrz/utils/http/MyTrustManager.java b/common/src/main/java/com/qmrz/utils/http/MyTrustManager.java new file mode 100644 index 0000000..5513f22 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/http/MyTrustManager.java @@ -0,0 +1,23 @@ +package com.qmrz.utils.http; + +import javax.net.ssl.X509TrustManager; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +/** + * 证书信任管理器(用于https请求) + * + * @author + * @date + */ +public class MyTrustManager implements X509TrustManager { + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + public X509Certificate[] getAcceptedIssuers() { + return null; + } +} diff --git a/common/src/main/java/com/qmrz/utils/proxy/HttpProxy.java b/common/src/main/java/com/qmrz/utils/proxy/HttpProxy.java new file mode 100644 index 0000000..b1331d6 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/proxy/HttpProxy.java @@ -0,0 +1,101 @@ +package com.qmrz.utils.proxy; + +import com.qmrz.utils.ReStreamInput; +import com.qmrz.utils.Web; +import com.qmrz.utils.http.MyTrustManager; +import lombok.extern.slf4j.Slf4j; +import net.coobird.thumbnailator.Thumbnails; + +import javax.imageio.ImageIO; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; + +/** + * http代理 + */ +@Slf4j +public class HttpProxy { + /** + * 响应http代理 + * + * @param httpURL + */ + public static void response(String httpURL) { + try { + Web.responseInputStream(getInputStream(httpURL)); + } catch (Exception e) { + log.warn(e.getMessage() + ",url:" + httpURL); + //e.printStackTrace(); + } + } + + /** + * 图片缩略图 + * + * @param httpURL + */ + public static void responseImageThumbnails(String httpURL) { + try { + ReStreamInput reStreamInput = new ReStreamInput(getInputStream(httpURL)); + InputStream is1 = reStreamInput.getInputStream(); + BufferedImage imageIO = ImageIO.read(is1); + + int w = imageIO.getWidth(); + int h = imageIO.getHeight(); + is1.close(); + is1 = null; + imageIO = null; + + if (w > 250) { + h = ((Double) (h / (w / 250d))).intValue(); + w = 250; + OutputStream stream = Web.getResponse().getOutputStream(); + Thumbnails.of(reStreamInput.getInputStream()).size(w, h).toOutputStream(stream); + stream.flush(); + stream.close(); + } else { + Web.responseInputStream(reStreamInput.getInputStream()); + } + } catch (Exception e) { + log.warn(e.getMessage() + ",url:" + httpURL); + //e.printStackTrace(); + } + } + + public static InputStream getInputStream(String httpURL) { + try { + URL url = new URL(httpURL); + URLConnection conn; + if ("https".equals(url.toURI().getScheme())) { + conn = url.openConnection(); + + HttpsURLConnection conns = (HttpsURLConnection) conn; + TrustManager[] tm = {new MyTrustManager()}; + SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); + sslContext.init(null, tm, new java.security.SecureRandom()); + conns.setSSLSocketFactory(sslContext.getSocketFactory()); + conns.setHostnameVerifier((hostname, sslsession) -> true); + } else { + conn = url.openConnection(); + } + + HttpURLConnection conn2 = (HttpURLConnection) conn; + conn2.setRequestMethod("GET"); + conn2.setConnectTimeout(5000); + conn2.setReadTimeout(5000); + return conn2.getInputStream(); + } catch (Exception e) { + log.warn(e.getMessage() + ",url:" + httpURL); + //e.printStackTrace(); + return null; + } + } +} diff --git a/common/src/main/java/com/qmrz/utils/proxy/ProxyServlet.java b/common/src/main/java/com/qmrz/utils/proxy/ProxyServlet.java new file mode 100644 index 0000000..3ef0c3d --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/proxy/ProxyServlet.java @@ -0,0 +1,713 @@ +package com.qmrz.utils.proxy; + +/* + * Copyright MITRE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpEntityEnclosingRequest; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.CookieSpecs; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.AbortableHttpRequest; +import org.apache.http.client.utils.URIUtils; +import org.apache.http.config.SocketConfig; +import org.apache.http.entity.InputStreamEntity; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicHttpEntityEnclosingRequest; +import org.apache.http.message.BasicHttpRequest; +import org.apache.http.message.HeaderGroup; +import org.apache.http.util.EntityUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.Closeable; +import java.io.IOException; +import java.io.OutputStream; +import java.net.HttpCookie; +import java.net.URI; +import java.util.BitSet; +import java.util.Enumeration; +import java.util.Formatter; + +/** + * An HTTP reverse proxy/gateway servlet. It is designed to be extended for customization + * if desired. Most of the work is handled by + * Apache HttpClient. + *

+ * There are alternatives to a servlet based proxy such as Apache mod_proxy if that is available to you. However + * this servlet is easily customizable by Java, secure-able by your web application's security (e.g. spring-security), + * portable across servlet engines, and is embeddable into another web application. + *

+ *

+ * Inspiration: http://httpd.apache.org/docs/2.0/mod/mod_proxy.html + *

+ * + * @author David Smiley dsmiley@apache.org + */ +@SuppressWarnings({ "deprecation", "serial" }) +public class ProxyServlet extends HttpServlet { + + /* INIT PARAMETER NAME CONSTANTS */ + + /** A boolean parameter name to enable logging of input and target URLs to the servlet log. */ + public static final String P_LOG = "log"; + + /** A boolean parameter name to enable forwarding of the client IP */ + public static final String P_FORWARDEDFOR = "forwardip"; + + /** A boolean parameter name to keep HOST parameter as-is */ + public static final String P_PRESERVEHOST = "preserveHost"; + + /** A boolean parameter name to keep COOKIES as-is */ + public static final String P_PRESERVECOOKIES = "preserveCookies"; + + /** A boolean parameter name to have auto-handle redirects */ + public static final String P_HANDLEREDIRECTS = "http.protocol.handle-redirects"; // ClientPNames.HANDLE_REDIRECTS + + /** A integer parameter name to set the socket connection timeout (millis) */ + public static final String P_CONNECTTIMEOUT = "http.socket.timeout"; // CoreConnectionPNames.SO_TIMEOUT + + /** A integer parameter name to set the socket read timeout (millis) */ + public static final String P_READTIMEOUT = "http.read.timeout"; + + /** A boolean parameter whether to use JVM-defined system properties to configure various networking aspects. */ + public static final String P_USESYSTEMPROPERTIES = "useSystemProperties"; + + /** The parameter name for the target (destination) URI to proxy to. */ + protected static final String P_TARGET_URI = "targetUri"; + protected static final String ATTR_TARGET_URI = + ProxyServlet.class.getSimpleName() + ".targetUri"; + protected static final String ATTR_TARGET_HOST = + ProxyServlet.class.getSimpleName() + ".targetHost"; + + /* MISC */ + + protected boolean doLog = false; + protected boolean doForwardIP = true; + /** User agents shouldn't send the url fragment but what if it does? */ + protected boolean doSendUrlFragment = true; + protected boolean doPreserveHost = false; + protected boolean doPreserveCookies = false; + protected boolean doHandleRedirects = false; + protected boolean useSystemProperties = false; + protected int connectTimeout = -1; + protected int readTimeout = -1; + + //These next 3 are cached here, and should only be referred to in initialization logic. See the + // ATTR_* parameters. + /** From the configured parameter "targetUri". */ + protected String targetUri; + protected URI targetUriObj;//new URI(targetUri) + protected HttpHost targetHost;//URIUtils.extractHost(targetUriObj); + + private HttpClient proxyClient; + + @Override + public String getServletInfo() { + return "A proxy servlet by David Smiley, dsmiley@apache.org"; + } + + + protected String getTargetUri(HttpServletRequest servletRequest) { + return (String) servletRequest.getAttribute(ATTR_TARGET_URI); + } + + protected HttpHost getTargetHost(HttpServletRequest servletRequest) { + return (HttpHost) servletRequest.getAttribute(ATTR_TARGET_HOST); + } + + /** + * Reads a configuration parameter. By default it reads servlet init parameters but + * it can be overridden. + */ + protected String getConfigParam(String key) { + return getServletConfig().getInitParameter(key); + } + + @Override + public void init() throws ServletException { + String doLogStr = getConfigParam(P_LOG); + if (doLogStr != null) { + this.doLog = Boolean.parseBoolean(doLogStr); + } + + String doForwardIPString = getConfigParam(P_FORWARDEDFOR); + if (doForwardIPString != null) { + this.doForwardIP = Boolean.parseBoolean(doForwardIPString); + } + + String preserveHostString = getConfigParam(P_PRESERVEHOST); + if (preserveHostString != null) { + this.doPreserveHost = Boolean.parseBoolean(preserveHostString); + } + + String preserveCookiesString = getConfigParam(P_PRESERVECOOKIES); + if (preserveCookiesString != null) { + this.doPreserveCookies = Boolean.parseBoolean(preserveCookiesString); + } + + String handleRedirectsString = getConfigParam(P_HANDLEREDIRECTS); + if (handleRedirectsString != null) { + this.doHandleRedirects = Boolean.parseBoolean(handleRedirectsString); + } + + String connectTimeoutString = getConfigParam(P_CONNECTTIMEOUT); + if (connectTimeoutString != null) { + this.connectTimeout = Integer.parseInt(connectTimeoutString); + } + + String readTimeoutString = getConfigParam(P_READTIMEOUT); + if (readTimeoutString != null) { + this.readTimeout = Integer.parseInt(readTimeoutString); + } + + String useSystemPropertiesString = getConfigParam(P_USESYSTEMPROPERTIES); + if (useSystemPropertiesString != null) { + this.useSystemProperties = Boolean.parseBoolean(useSystemPropertiesString); + } + + initTarget();//sets target* + + proxyClient = createHttpClient(); + } + + /** + * Sub-classes can override specific behaviour of {@link org.apache.http.client.config.RequestConfig}. + */ + protected RequestConfig buildRequestConfig() { + return RequestConfig.custom() + .setRedirectsEnabled(doHandleRedirects) + .setCookieSpec(CookieSpecs.IGNORE_COOKIES) // we handle them in the servlet instead + .setConnectTimeout(connectTimeout) + .setSocketTimeout(readTimeout) + .build(); + } + + /** + * Sub-classes can override specific behaviour of {@link org.apache.http.config.SocketConfig}. + */ + protected SocketConfig buildSocketConfig() { + + if (readTimeout < 1) { + return null; + } + + return SocketConfig.custom() + .setSoTimeout(readTimeout) + .build(); + } + + protected void initTarget() throws ServletException { + targetUri = getConfigParam(P_TARGET_URI); + if (targetUri == null) + throw new ServletException(P_TARGET_URI+" is required."); + //test it's valid + try { + targetUriObj = new URI(targetUri); + } catch (Exception e) { + throw new ServletException("Trying to process targetUri init parameter: "+e,e); + } + targetHost = URIUtils.extractHost(targetUriObj); + } + + /** + * Called from {@link #init(javax.servlet.ServletConfig)}. + * HttpClient offers many opportunities for customization. + * In any case, it should be thread-safe. + */ + protected HttpClient createHttpClient() { + HttpClientBuilder clientBuilder = HttpClientBuilder.create() + .setDefaultRequestConfig(buildRequestConfig()) + .setDefaultSocketConfig(buildSocketConfig()); + if (useSystemProperties) + clientBuilder = clientBuilder.useSystemProperties(); + return clientBuilder.build(); + } + + /** + * The http client used. + * @see #createHttpClient() + */ + protected HttpClient getProxyClient() { + return proxyClient; + } + + @Override + public void destroy() { + //Usually, clients implement Closeable: + if (proxyClient instanceof Closeable) { + try { + ((Closeable) proxyClient).close(); + } catch (IOException e) { + log("While destroying servlet, shutting down HttpClient: "+e, e); + } + } else { + //Older releases require we do this: + if (proxyClient != null) + proxyClient.getConnectionManager().shutdown(); + } + super.destroy(); + } + + @Override + protected void service(HttpServletRequest servletRequest, HttpServletResponse servletResponse) + throws ServletException, IOException { + //initialize request attributes from caches if unset by a subclass by this point + if (servletRequest.getAttribute(ATTR_TARGET_URI) == null) { + servletRequest.setAttribute(ATTR_TARGET_URI, targetUri); + } + if (servletRequest.getAttribute(ATTR_TARGET_HOST) == null) { + servletRequest.setAttribute(ATTR_TARGET_HOST, targetHost); + } + + // Make the Request + //note: we won't transfer the protocol version because I'm not sure it would truly be compatible + String method = servletRequest.getMethod(); + String proxyRequestUri = rewriteUrlFromRequest(servletRequest); + HttpRequest proxyRequest; + //spec: RFC 2616, sec 4.3: either of these two headers signal that there is a message body. + if (servletRequest.getHeader(HttpHeaders.CONTENT_LENGTH) != null || + servletRequest.getHeader(HttpHeaders.TRANSFER_ENCODING) != null) { + proxyRequest = newProxyRequestWithEntity(method, proxyRequestUri, servletRequest); + } else { + proxyRequest = new BasicHttpRequest(method, proxyRequestUri); + } + + copyRequestHeaders(servletRequest, proxyRequest); + + setXForwardedForHeader(servletRequest, proxyRequest); + + HttpResponse proxyResponse = null; + try { + // Execute the request + proxyResponse = doExecute(servletRequest, servletResponse, proxyRequest); + + // Process the response: + + // Pass the response code. This method with the "reason phrase" is deprecated but it's the + // only way to pass the reason along too. + int statusCode = proxyResponse.getStatusLine().getStatusCode(); + //noinspection deprecation + servletResponse.setStatus(statusCode, proxyResponse.getStatusLine().getReasonPhrase()); + + // Copying response headers to make sure SESSIONID or other Cookie which comes from the remote + // server will be saved in client when the proxied url was redirected to another one. + // See issue [#51](https://github.com/mitre/HTTP-Proxy-Servlet/issues/51) + copyResponseHeaders(proxyResponse, servletRequest, servletResponse); + + if (statusCode == HttpServletResponse.SC_NOT_MODIFIED) { + // 304 needs special handling. See: + // http://www.ics.uci.edu/pub/ietf/http/rfc1945.html#Code304 + // Don't send body entity/content! + servletResponse.setIntHeader(HttpHeaders.CONTENT_LENGTH, 0); + } else { + // Send the content to the client + copyResponseEntity(proxyResponse, servletResponse, proxyRequest, servletRequest); + } + + } catch (Exception e) { + handleRequestException(proxyRequest, e); + } finally { + // make sure the entire entity was consumed, so the connection is released + if (proxyResponse != null) + EntityUtils.consumeQuietly(proxyResponse.getEntity()); + //Note: Don't need to close servlet outputStream: + // http://stackoverflow.com/questions/1159168/should-one-call-close-on-httpservletresponse-getoutputstream-getwriter + } + } + + protected void handleRequestException(HttpRequest proxyRequest, Exception e) throws ServletException, IOException { + //abort request, according to best practice with HttpClient + if (proxyRequest instanceof AbortableHttpRequest) { + AbortableHttpRequest abortableHttpRequest = (AbortableHttpRequest) proxyRequest; + abortableHttpRequest.abort(); + } + if (e instanceof RuntimeException) + throw (RuntimeException)e; + if (e instanceof ServletException) + throw (ServletException)e; + //noinspection ConstantConditions + if (e instanceof IOException) + throw (IOException) e; + throw new RuntimeException(e); + } + + protected HttpResponse doExecute(HttpServletRequest servletRequest, HttpServletResponse servletResponse, + HttpRequest proxyRequest) throws IOException { + if (doLog) { + log("proxy " + servletRequest.getMethod() + " uri: " + servletRequest.getRequestURI() + " -- " + + proxyRequest.getRequestLine().getUri()); + } + return proxyClient.execute(getTargetHost(servletRequest), proxyRequest); + } + + protected HttpRequest newProxyRequestWithEntity(String method, String proxyRequestUri, + HttpServletRequest servletRequest) + throws IOException { + HttpEntityEnclosingRequest eProxyRequest = + new BasicHttpEntityEnclosingRequest(method, proxyRequestUri); + // Add the input entity (streamed) + // note: we don't bother ensuring we close the servletInputStream since the container handles it + eProxyRequest.setEntity( + new InputStreamEntity(servletRequest.getInputStream(), getContentLength(servletRequest))); + return eProxyRequest; + } + + // Get the header value as a long in order to more correctly proxy very large requests + private long getContentLength(HttpServletRequest request) { + String contentLengthHeader = request.getHeader("Content-Length"); + if (contentLengthHeader != null) { + return Long.parseLong(contentLengthHeader); + } + return -1L; + } + + protected void closeQuietly(Closeable closeable) { + try { + closeable.close(); + } catch (IOException e) { + log(e.getMessage(), e); + } + } + + /** These are the "hop-by-hop" headers that should not be copied. + * http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html + * I use an HttpClient HeaderGroup class instead of Set<String> because this + * approach does case insensitive lookup faster. + */ + protected static final HeaderGroup hopByHopHeaders; + static { + hopByHopHeaders = new HeaderGroup(); + String[] headers = new String[] { + "Connection", "Keep-Alive", "Proxy-Authenticate", "Proxy-Authorization", + "TE", "Trailers", "Transfer-Encoding", "Upgrade" }; + for (String header : headers) { + hopByHopHeaders.addHeader(new BasicHeader(header, null)); + } + } + + /** + * Copy request headers from the servlet client to the proxy request. + * This is easily overridden to add your own. + */ + protected void copyRequestHeaders(HttpServletRequest servletRequest, HttpRequest proxyRequest) { + // Get an Enumeration of all of the header names sent by the client + @SuppressWarnings("unchecked") + Enumeration enumerationOfHeaderNames = servletRequest.getHeaderNames(); + while (enumerationOfHeaderNames.hasMoreElements()) { + String headerName = enumerationOfHeaderNames.nextElement(); + copyRequestHeader(servletRequest, proxyRequest, headerName); + } + } + + /** + * Copy a request header from the servlet client to the proxy request. + * This is easily overridden to filter out certain headers if desired. + */ + protected void copyRequestHeader(HttpServletRequest servletRequest, HttpRequest proxyRequest, + String headerName) { + //Instead the content-length is effectively set via InputStreamEntity + if (headerName.equalsIgnoreCase(HttpHeaders.CONTENT_LENGTH)) + return; + if (hopByHopHeaders.containsHeader(headerName)) + return; + + @SuppressWarnings("unchecked") + Enumeration headers = servletRequest.getHeaders(headerName); + while (headers.hasMoreElements()) {//sometimes more than one value + String headerValue = headers.nextElement(); + // In case the proxy host is running multiple virtual servers, + // rewrite the Host header to ensure that we get content from + // the correct virtual server + if (!doPreserveHost && headerName.equalsIgnoreCase(HttpHeaders.HOST)) { + HttpHost host = getTargetHost(servletRequest); + headerValue = host.getHostName(); + if (host.getPort() != -1) + headerValue += ":"+host.getPort(); + } else if (!doPreserveCookies && headerName.equalsIgnoreCase(org.apache.http.cookie.SM.COOKIE)) { + headerValue = getRealCookie(headerValue); + } + proxyRequest.addHeader(headerName, headerValue); + } + } + + private void setXForwardedForHeader(HttpServletRequest servletRequest, + HttpRequest proxyRequest) { + if (doForwardIP) { + String forHeaderName = "X-Forwarded-For"; + String forHeader = servletRequest.getRemoteAddr(); + String existingForHeader = servletRequest.getHeader(forHeaderName); + if (existingForHeader != null) { + forHeader = existingForHeader + ", " + forHeader; + } + proxyRequest.setHeader(forHeaderName, forHeader); + + String protoHeaderName = "X-Forwarded-Proto"; + String protoHeader = servletRequest.getScheme(); + proxyRequest.setHeader(protoHeaderName, protoHeader); + } + } + + /** Copy proxied response headers back to the servlet client. */ + protected void copyResponseHeaders(HttpResponse proxyResponse, HttpServletRequest servletRequest, + HttpServletResponse servletResponse) { + for (Header header : proxyResponse.getAllHeaders()) { + copyResponseHeader(servletRequest, servletResponse, header); + } + } + + /** Copy a proxied response header back to the servlet client. + * This is easily overwritten to filter out certain headers if desired. + */ + protected void copyResponseHeader(HttpServletRequest servletRequest, + HttpServletResponse servletResponse, Header header) { + String headerName = header.getName(); + if (hopByHopHeaders.containsHeader(headerName)) + return; + String headerValue = header.getValue(); + if (headerName.equalsIgnoreCase(org.apache.http.cookie.SM.SET_COOKIE) || + headerName.equalsIgnoreCase(org.apache.http.cookie.SM.SET_COOKIE2)) { + copyProxyCookie(servletRequest, servletResponse, headerValue); + } else if (headerName.equalsIgnoreCase(HttpHeaders.LOCATION)) { + // LOCATION Header may have to be rewritten. + servletResponse.addHeader(headerName, rewriteUrlFromResponse(servletRequest, headerValue)); + } else { + servletResponse.addHeader(headerName, headerValue); + } + } + + /** + * Copy cookie from the proxy to the servlet client. + * Replaces cookie path to local path and renames cookie to avoid collisions. + */ + protected void copyProxyCookie(HttpServletRequest servletRequest, + HttpServletResponse servletResponse, String headerValue) { + //build path for resulting cookie + String path = servletRequest.getContextPath(); // path starts with / or is empty string + path += servletRequest.getServletPath(); // servlet path starts with / or is empty string + if(path.isEmpty()){ + path = "/"; + } + + for (HttpCookie cookie : HttpCookie.parse(headerValue)) { + //set cookie name prefixed w/ a proxy value so it won't collide w/ other cookies + String proxyCookieName = doPreserveCookies ? cookie.getName() : getCookieNamePrefix(cookie.getName()) + cookie.getName(); + Cookie servletCookie = new Cookie(proxyCookieName, cookie.getValue()); + servletCookie.setComment(cookie.getComment()); + servletCookie.setMaxAge((int) cookie.getMaxAge()); + servletCookie.setPath(path); //set to the path of the proxy servlet + // don't set cookie domain + servletCookie.setSecure(cookie.getSecure()); + servletCookie.setVersion(cookie.getVersion()); + servletCookie.setHttpOnly(cookie.isHttpOnly()); + servletResponse.addCookie(servletCookie); + } + } + + /** + * Take any client cookies that were originally from the proxy and prepare them to send to the + * proxy. This relies on cookie headers being set correctly according to RFC 6265 Sec 5.4. + * This also blocks any local cookies from being sent to the proxy. + */ + protected String getRealCookie(String cookieValue) { + StringBuilder escapedCookie = new StringBuilder(); + String cookies[] = cookieValue.split("[;,]"); + for (String cookie : cookies) { + String cookieSplit[] = cookie.split("="); + if (cookieSplit.length == 2) { + String cookieName = cookieSplit[0].trim(); + if (cookieName.startsWith(getCookieNamePrefix(cookieName))) { + cookieName = cookieName.substring(getCookieNamePrefix(cookieName).length()); + if (escapedCookie.length() > 0) { + escapedCookie.append("; "); + } + escapedCookie.append(cookieName).append("=").append(cookieSplit[1].trim()); + } + } + } + return escapedCookie.toString(); + } + + /** The string prefixing rewritten cookies. */ + protected String getCookieNamePrefix(String name) { + return "!Proxy!" + getServletConfig().getServletName(); + } + + /** Copy response body data (the entity) from the proxy to the servlet client. */ + protected void copyResponseEntity(HttpResponse proxyResponse, HttpServletResponse servletResponse, + HttpRequest proxyRequest, HttpServletRequest servletRequest) + throws IOException { + HttpEntity entity = proxyResponse.getEntity(); + if (entity != null) { + OutputStream servletOutputStream = servletResponse.getOutputStream(); + entity.writeTo(servletOutputStream); + } + } + + /** + * Reads the request URI from {@code servletRequest} and rewrites it, considering targetUri. + * It's used to make the new request. + */ + protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) { + StringBuilder uri = new StringBuilder(500); + uri.append(getTargetUri(servletRequest)); + // Handle the path given to the servlet + String pathInfo = servletRequest.getPathInfo(); + if (pathInfo != null) {//ex: /my/path.html + // getPathInfo() returns decoded string, so we need encodeUriQuery to encode "%" characters + uri.append(encodeUriQuery(pathInfo, true)); + } + // Handle the query string & fragment + String queryString = servletRequest.getQueryString();//ex:(following '?'): name=value&foo=bar#fragment + String fragment = null; + //split off fragment from queryString, updating queryString if found + if (queryString != null) { + int fragIdx = queryString.indexOf('#'); + if (fragIdx >= 0) { + fragment = queryString.substring(fragIdx + 1); + queryString = queryString.substring(0,fragIdx); + } + } + + queryString = rewriteQueryStringFromRequest(servletRequest, queryString); + if (queryString != null && queryString.length() > 0) { + uri.append('?'); + // queryString is not decoded, so we need encodeUriQuery not to encode "%" characters, to avoid double-encoding + uri.append(encodeUriQuery(queryString, false)); + } + + if (doSendUrlFragment && fragment != null) { + uri.append('#'); + // fragment is not decoded, so we need encodeUriQuery not to encode "%" characters, to avoid double-encoding + uri.append(encodeUriQuery(fragment, false)); + } + return uri.toString(); + } + + protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) { + return queryString; + } + + /** + * For a redirect response from the target server, this translates {@code theUrl} to redirect to + * and translates it to one the original client can use. + */ + protected String rewriteUrlFromResponse(HttpServletRequest servletRequest, String theUrl) { + //TODO document example paths + final String targetUri = getTargetUri(servletRequest); + if (theUrl.startsWith(targetUri)) { + /*- + * The URL points back to the back-end server. + * Instead of returning it verbatim we replace the target path with our + * source path in a way that should instruct the original client to + * request the URL pointed through this Proxy. + * We do this by taking the current request and rewriting the path part + * using this servlet's absolute path and the path from the returned URL + * after the base target URL. + */ + StringBuffer curUrl = servletRequest.getRequestURL();//no query + int pos; + // Skip the protocol part + if ((pos = curUrl.indexOf("://"))>=0) { + // Skip the authority part + // + 3 to skip the separator between protocol and authority + if ((pos = curUrl.indexOf("/", pos + 3)) >=0) { + // Trim everything after the authority part. + curUrl.setLength(pos); + } + } + // Context path starts with a / if it is not blank + curUrl.append(servletRequest.getContextPath()); + // Servlet path starts with a / if it is not blank + curUrl.append(servletRequest.getServletPath()); + curUrl.append(theUrl, targetUri.length(), theUrl.length()); + return curUrl.toString(); + } + return theUrl; + } + + /** The target URI as configured. Not null. */ + public String getTargetUri() { return targetUri; } + + /** + * Encodes characters in the query or fragment part of the URI. + * + *

Unfortunately, an incoming URI sometimes has characters disallowed by the spec. HttpClient + * insists that the outgoing proxied request has a valid URI because it uses Java's {@link URI}. + * To be more forgiving, we must escape the problematic characters. See the URI class for the + * spec. + * + * @param in example: name=value&foo=bar#fragment + * @param encodePercent determine whether percent characters need to be encoded + */ + protected static CharSequence encodeUriQuery(CharSequence in, boolean encodePercent) { + //Note that I can't simply use URI.java to encode because it will escape pre-existing escaped things. + StringBuilder outBuf = null; + Formatter formatter = null; + for(int i = 0; i < in.length(); i++) { + char c = in.charAt(i); + boolean escape = true; + if (c < 128) { + if (asciiQueryChars.get((int)c) && !(encodePercent && c == '%')) { + escape = false; + } + } else if (!Character.isISOControl(c) && !Character.isSpaceChar(c)) {//not-ascii + escape = false; + } + if (!escape) { + if (outBuf != null) + outBuf.append(c); + } else { + //escape + if (outBuf == null) { + outBuf = new StringBuilder(in.length() + 5*3); + outBuf.append(in,0,i); + formatter = new Formatter(outBuf); + } + //leading %, 0 padded, width 2, capital hex + formatter.format("%%%02X",(int)c);//TODO + } + } + return outBuf != null ? outBuf : in; + } + + protected static final BitSet asciiQueryChars; + static { + char[] c_unreserved = "_-!.~'()*".toCharArray();//plus alphanum + char[] c_punct = ",;:$&+=".toCharArray(); + char[] c_reserved = "?/[]@".toCharArray();//plus punct + + asciiQueryChars = new BitSet(128); + for(char c = 'a'; c <= 'z'; c++) asciiQueryChars.set((int)c); + for(char c = 'A'; c <= 'Z'; c++) asciiQueryChars.set((int)c); + for(char c = '0'; c <= '9'; c++) asciiQueryChars.set((int)c); + for(char c : c_unreserved) asciiQueryChars.set((int)c); + for(char c : c_punct) asciiQueryChars.set((int)c); + for(char c : c_reserved) asciiQueryChars.set((int)c); + + asciiQueryChars.set((int)'%');//leave existing percent escapes in place + } + +} diff --git a/common/src/main/java/com/qmrz/utils/proxy/URITemplateProxyServlet.java b/common/src/main/java/com/qmrz/utils/proxy/URITemplateProxyServlet.java new file mode 100644 index 0000000..2ce612a --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/proxy/URITemplateProxyServlet.java @@ -0,0 +1,146 @@ +package com.qmrz.utils.proxy; + +/* + * Copyright MITRE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URIUtils; +import org.apache.http.client.utils.URLEncodedUtils; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A proxy servlet in which the target URI is templated from incoming request parameters. The + * format adheres to the URI Template RFC, "Level + * 1". Example: + *

+ *   targetUri = http://{host}:{port}/{path}
+ * 
+ * --which has the template variables. The incoming request must contain query args of these + * names. They are removed when the request is sent to the target. + */ +@SuppressWarnings({"serial"}) +public class URITemplateProxyServlet extends ProxyServlet { + + /* Rich: + * It might be a nice addition to have some syntax that allowed a proxy arg to be "optional", that is, + * don't fail if not present, just return the empty string or a given default. But I don't see + * anything in the spec that supports this kind of construct. + * Notionally, it might look like {?host:google.com} would return the value of + * the URL parameter "?hostProxyArg=somehost.com" if defined, but if not defined, return "google.com". + * Similarly, {?host} could return the value of hostProxyArg or empty string if not present. + * But that's not how the spec works. So for now we will require a proxy arg to be present + * if defined for this proxy URL. + */ + protected static final Pattern TEMPLATE_PATTERN = Pattern.compile("\\{(.+?)\\}"); + private static final String ATTR_QUERY_STRING = + URITemplateProxyServlet.class.getSimpleName() + ".queryString"; + + protected String targetUriTemplate;//has {name} parts + + @Override + protected void initTarget() throws ServletException { + targetUriTemplate = getConfigParam(P_TARGET_URI); + if (targetUriTemplate == null) + throw new ServletException(P_TARGET_URI+" is required."); + + //leave this.target* null to prevent accidental mis-use + } + + @Override + protected void service(HttpServletRequest servletRequest, HttpServletResponse servletResponse) + throws ServletException, IOException { + + //First collect params + /* + * Do not use servletRequest.getParameter(arg) because that will + * typically read and consume the servlet InputStream (where our + * form data is stored for POST). We need the InputStream later on. + * So we'll parse the query string ourselves. A side benefit is + * we can keep the proxy parameters in the query string and not + * have to add them to a URL encoded form attachment. + */ + String requestQueryString = servletRequest.getQueryString(); + String queryString = ""; + if (requestQueryString != null) { + queryString = "?" + requestQueryString;//no "?" but might have "#" + } + int hash = queryString.indexOf('#'); + if (hash >= 0) { + queryString = queryString.substring(0, hash); + } + List pairs; + try { + //note: HttpClient 4.2 lets you parse the string without building the URI + pairs = URLEncodedUtils.parse(new URI(queryString), "UTF-8"); + } catch (URISyntaxException e) { + throw new ServletException("Unexpected URI parsing error on " + queryString, e); + } + LinkedHashMap params = new LinkedHashMap(); + for (NameValuePair pair : pairs) { + params.put(pair.getName(), pair.getValue()); + } + + //Now rewrite the URL + StringBuffer urlBuf = new StringBuffer();//note: StringBuilder isn't supported by Matcher + Matcher matcher = TEMPLATE_PATTERN.matcher(targetUriTemplate); + while (matcher.find()) { + String arg = matcher.group(1); + String replacement = params.remove(arg);//note we remove + if (replacement == null) { + throw new ServletException("Missing HTTP parameter "+arg+" to fill the template"); + } + matcher.appendReplacement(urlBuf, replacement); + } + matcher.appendTail(urlBuf); + String newTargetUri = urlBuf.toString(); + servletRequest.setAttribute(ATTR_TARGET_URI, newTargetUri); + URI targetUriObj; + try { + targetUriObj = new URI(newTargetUri); + } catch (Exception e) { + throw new ServletException("Rewritten targetUri is invalid: " + newTargetUri,e); + } + servletRequest.setAttribute(ATTR_TARGET_HOST, URIUtils.extractHost(targetUriObj)); + + //Determine the new query string based on removing the used names + StringBuilder newQueryBuf = new StringBuilder(queryString.length()); + for (Map.Entry nameVal : params.entrySet()) { + if (newQueryBuf.length() > 0) + newQueryBuf.append('&'); + newQueryBuf.append(nameVal.getKey()).append('='); + if (nameVal.getValue() != null) + newQueryBuf.append(nameVal.getValue()); + } + servletRequest.setAttribute(ATTR_QUERY_STRING, newQueryBuf.toString()); + + super.service(servletRequest, servletResponse); + } + + @Override + protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) { + return (String) servletRequest.getAttribute(ATTR_QUERY_STRING); + } +} diff --git a/common/src/main/java/com/qmrz/utils/shiro/IShiroRealm.java b/common/src/main/java/com/qmrz/utils/shiro/IShiroRealm.java new file mode 100644 index 0000000..ef95bad --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/shiro/IShiroRealm.java @@ -0,0 +1,5 @@ +package com.qmrz.utils.shiro; + +public interface IShiroRealm { + void clearAuth(); +} diff --git a/common/src/main/java/com/qmrz/utils/shiro/ShiroUtil.java b/common/src/main/java/com/qmrz/utils/shiro/ShiroUtil.java new file mode 100644 index 0000000..b16e1fe --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/shiro/ShiroUtil.java @@ -0,0 +1,33 @@ +package com.qmrz.utils.shiro; + +import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.mgt.RealmSecurityManager; +import org.apache.shiro.realm.AuthorizingRealm; +import org.apache.shiro.subject.SimplePrincipalCollection; +import org.apache.shiro.subject.Subject; + +@Slf4j +public class ShiroUtil { + public void reflush(String principal){ + RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager(); +//AccountAuthorizationRealm为在项目中定义的realm类 + AuthorizingRealm shiroRealm = (AuthorizingRealm)rsm.getRealms().iterator().next(); + Subject subject = SecurityUtils.getSubject(); + String realmName = subject.getPrincipals().getRealmNames().iterator().next(); + SimplePrincipalCollection principals = new SimplePrincipalCollection(principal,realmName); + subject.runAs(principals); +//用realm删除principle + shiroRealm.getAuthorizationCache().remove(subject.getPrincipal()); + shiroRealm.getAuthorizationCache().remove(subject.getPrincipals()); +//切换身份也就是刷新了 + subject.releaseRunAs(); + } + + public static void clearAuth(){ + log.info("clearAuth"); + RealmSecurityManager rsm = (RealmSecurityManager)SecurityUtils.getSecurityManager(); + IShiroRealm realm = (IShiroRealm)rsm.getRealms().iterator().next(); + realm.clearAuth(); + } +} diff --git a/common/src/main/java/com/qmrz/utils/tree/TreeBuilder.java b/common/src/main/java/com/qmrz/utils/tree/TreeBuilder.java new file mode 100644 index 0000000..9ab9ed3 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/tree/TreeBuilder.java @@ -0,0 +1,296 @@ +package com.qmrz.utils.tree; + +import com.qmrz.mybatis.POUtil; +import com.qmrz.utils.Fn; +import com.qmrz.utils.MapChain; +import com.qmrz.utils.MapUtil; +import org.apache.commons.lang.StringUtils; +import org.apache.ibatis.reflection.MetaObject; +import org.apache.ibatis.reflection.SystemMetaObject; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * 分级信息树(如:无限级分类,省市等),构建树、扁平化、结点路径等功能 + * @param + */ +public class TreeBuilder { + /** + * 组织及扁平化后的原始数据 + */ + private List flatData = new ArrayList<>(); + + /** + * 组后及扁平化后的树结点 + */ + private List> flatTree = new ArrayList<>(); + + /** + * 初始结点(未组织过的无序列表) + */ + private List> treeNodes;//初始tree + + /** + * 组织后的树 + */ + private List> treeList;//按分级重组后 + + public TreeBuilder(List data) { + this.treeNodes = new ArrayList<>(); + + for (T item : data) { + MetaObject msObject = SystemMetaObject.forObject(item); + int id = Integer.parseInt(msObject.getValue("id").toString()); + int pid = Integer.parseInt(msObject.getValue("pid").toString()); + this.treeNodes.add(new TreeNode(id, pid, item)); + } + + //构建树 + this.treeList = bulid(); + + //将会初始化flatData、flatTree + this.loadFlatData(this.treeList, 0); + } + + /** + * 根据List集合每一行的分类infoclassid,获得一个分类路径结果集,用与前端展示 + * 请确保List每行的实体有id和infoclassid字段 + * + * @param list + * @param split + * @return Map 行id,分类路径名 + */ + public Map addClass(Object originData,List list, String split) { + MapChain path = MapUtil.newMap(); + for (Object item : list) { + MetaObject mo = SystemMetaObject.forObject(item); + Object id = mo.getValue("id"); + int infoclassid = Fn.toInt(mo.getValue("infoclassid")); + path.put(id.toString(), pathString(infoclassid, split)); + } + + MapChain mc = MapUtil.newMap(POUtil.getMap(originData)).put("path", path.getMap()); + return mc.getMap(); + } + + /** + * 判断结点是否在指定树(枝)里(判断 searchID 在 originID 树里是否存在) + * + * @param originID + * @param searchID + * @return + */ + public boolean contain(int originID, int searchID) { + List> list = getTreeFlatList(originID); + for (TreeNode item : list) { + if (item.getId().equals(searchID)) { + return true; + } + } + return false; + } + + /** + * 获取id下结点的所有id,包括 + * @param id + * @return + */ + public List treeIDList(int id) { + List list = new ArrayList<>(); + getTreeFlatList(id).forEach(item->list.add(item.getId())); + return list; + } + + /** + * 获取id下结点数量(含id) + * @param id + * @return + */ + public int treeCount(int id) { + return getTreeFlatList(id).size(); + } + + /** + * 根据id获取树结点 + * @param id + * @return + */ + public TreeNode findByID(int id) { + for (TreeNode item : flatTree) { + if (id == item.getId()) { + return item; + } + } + return null; + } + + /** + * 根据id获取所在路径字符串(含id) + * @param id + * @param split 路径结点分隔符 + * @return + */ + public String pathString(int id, String split) { + List list = pathTree(id); + List strList = new ArrayList<>(); + for (T item : list) { + String str = SystemMetaObject.forObject(item).getValue("name").toString(); + strList.add(str); + } + return StringUtils.join(strList.toArray(), split); + } + + /** + * 给一个id,获取路径的每个节点集合 + * + * @param id + * @return + */ + public List pathTree(int id) { + List> list = new ArrayList<>(); + pathTree(list, id); + + List result = new ArrayList<>(); + for (TreeNode item : list) { + result.add(item.getItem()); + } + Collections.reverse(result); + return result; + } + + /** + * 给一个id,获取路径的每个节点集合 + * + * @param pathList + * @param id + */ + private void pathTree(List> pathList, int id) { + TreeNode node = findByID(id); + if (node == null) { + return; + } + pathList.add(node); + + for (TreeNode item : flatTree) { + if (item.getId().equals(node.getPid())) { + pathTree(pathList, item.getId()); + } + } + } + + /** + * 根据id获取此类目下(含)的所有类目的扁平化【源数据】列表 + * + * @param id + * @return + */ + public List getFlatDataList(int id) { + List newList = new ArrayList<>(); + List> list = getTreeFlatList(id); + for (TreeNode item : list) { + newList.add(item.getItem()); + } + return newList; + } + + + /** + * 根据id获取此类目下(含)的所有类目的扁平化【树】列表 + * + * @param id + * @return + */ + public List> getTreeFlatList(int id) { + List> newList = new ArrayList<>(); + getFlatList(id, false, this.treeList, newList); + return newList; + } + + /** + * 根据id查询子树 + * + * @param id + * @param isFind 是否找到,若找到则此节点的所有子节点都加入 + * @param list + * @param newList + */ + private void getFlatList(int id, boolean isFind, List> list, List> newList) { + for (TreeNode item : list) { + boolean tmpIsFind = false || isFind; + if (item.getId().equals(id)) { + tmpIsFind = true; + } + + if (tmpIsFind) { + newList.add(item); + } + + if (item.getChildren() != null) { + getFlatList(id, tmpIsFind, item.getChildren(), newList); + } + } + } + + /** + * 将重组好后的树扁平化 + * + * @param list + */ + private void loadFlatData(List> list, int level) { + for (TreeNode item : list) { + item.setLevel(level); + SystemMetaObject.forObject(item.getItem()).setValue("level", level); + this.flatData.add(item.getItem()); + this.flatTree.add(item); + if (item.getChildren() != null) { + loadFlatData(item.getChildren(), level + 1); + } + } + } + + /** + * 重组好后的树 + * + * @return + */ + public List> getTreeList() { + return treeList; + } + + /** + * 将重组好后的树扁平化 + * + * @return + */ + public List getFlatData() { + return flatData; + } + + /** + * 构建一颗树 + * + * @return + */ + private List> bulid() { + List> trees = new ArrayList<>(); + for (TreeNode treeNode : treeNodes) { + if (0 == treeNode.getPid()) { + trees.add(treeNode); + } + + for (TreeNode it : treeNodes) { + if (it.getPid().equals(treeNode.getId())) { + if (treeNode.getChildren() == null) { + treeNode.setChildren(new ArrayList<>()); + } + treeNode.getChildren().add(it); + } + } + } + return trees; + } + +} diff --git a/common/src/main/java/com/qmrz/utils/tree/TreeNode.java b/common/src/main/java/com/qmrz/utils/tree/TreeNode.java new file mode 100644 index 0000000..e455e90 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/tree/TreeNode.java @@ -0,0 +1,20 @@ +package com.qmrz.utils.tree; + +import lombok.Data; + +import java.util.List; + +@Data +public class TreeNode { + private Integer id; + private Integer pid; + private T item; + private Integer level; + private List> children; + + public TreeNode(int id, int pid, T item) { + this.id = id; + this.pid = pid; + this.item = item; + } +} diff --git a/common/src/main/java/com/qmrz/utils/validate/Phone.java b/common/src/main/java/com/qmrz/utils/validate/Phone.java new file mode 100644 index 0000000..387536e --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/validate/Phone.java @@ -0,0 +1,17 @@ +package com.qmrz.utils.validate; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.*; + +@Constraint(validatedBy = PhoneValidate.class) +@Target({ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Phone { + String message() default "手机号码格式不正确"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/common/src/main/java/com/qmrz/utils/validate/PhoneMulti.java b/common/src/main/java/com/qmrz/utils/validate/PhoneMulti.java new file mode 100644 index 0000000..148ae9e --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/validate/PhoneMulti.java @@ -0,0 +1,17 @@ +package com.qmrz.utils.validate; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.*; + +@Constraint(validatedBy = PhoneMultiValidate.class) +@Target({ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface PhoneMulti { + String message() default "手机号码格式不正确"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/common/src/main/java/com/qmrz/utils/validate/PhoneMultiValidate.java b/common/src/main/java/com/qmrz/utils/validate/PhoneMultiValidate.java new file mode 100644 index 0000000..7fa3d8a --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/validate/PhoneMultiValidate.java @@ -0,0 +1,18 @@ +package com.qmrz.utils.validate; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.util.regex.Pattern; + +public class PhoneMultiValidate implements ConstraintValidator { + + private Pattern pattern = Pattern.compile("^(,?[1][0-9]{10})+$"); + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + if (value == null) { + return false; + } + return pattern.matcher(value).matches(); + } +} diff --git a/common/src/main/java/com/qmrz/utils/validate/PhoneValidate.java b/common/src/main/java/com/qmrz/utils/validate/PhoneValidate.java new file mode 100644 index 0000000..f3841c8 --- /dev/null +++ b/common/src/main/java/com/qmrz/utils/validate/PhoneValidate.java @@ -0,0 +1,18 @@ +package com.qmrz.utils.validate; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.util.regex.Pattern; + +public class PhoneValidate implements ConstraintValidator { + + private Pattern pattern = Pattern.compile("^[1][0-9,]{10}$"); + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + if (value == null) { + return false; + } + return pattern.matcher(value).matches(); + } +} diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..60c28cd --- /dev/null +++ b/pom.xml @@ -0,0 +1,372 @@ + + + 4.0.0 + + com.qmrz + codeGenerate + pom + 1.0 + + + + ab + http://maven.aliyun.com/nexus/content/groups/public/ + + + + + ab + http://maven.aliyun.com/nexus/content/groups/public/ + + + + 代码生成器 + + common + service + + + + + + + + + + + + org.springframework.boot + spring-boot-starter-parent + 2.0.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-tomcat + provided + + + + + + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + org.springframework.session + spring-session-data-redis + + + + + + + + + + + org.springframework.boot + spring-boot-starter-websocket + + + + + org.java-websocket + Java-WebSocket + 1.3.8 + + + + com.github.signalr4j + signalr4j + 2.0.3 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + + + org.springframework.boot + spring-boot-starter-freemarker + + + + com.googlecode.rapid-framework + rapid-core + 4.0.4 + + + + commons-lang + commons-lang + 2.6 + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 1.3.2 + + + + + + + + + + + + + + + + + tk.mybatis + mapper + 4.0.0 + + + + + + + + + + org.hibernate + hibernate-validator + 6.0.10.Final + + + + com.github.pagehelper + pagehelper + 5.1.4 + + + + org.springframework.boot + spring-boot-starter-aop + + + + org.springframework.boot + spring-boot-starter-cache + + + + + + + + + + + + + + com.alibaba + druid + 1.1.9 + + + + mysql + mysql-connector-java + 8.0.11 + + + + + + + + + + + com.alibaba + fastjson + 1.2.47 + + + + + org.projectlombok + lombok + 1.16.20 + provided + + + + commons-io + commons-io + 2.6 + + + + org.apache.shiro + shiro-spring + 1.4.0 + + + + commons-codec + commons-codec + 1.11 + + + + net.sf.ehcache + ehcache + + + + dom4j + dom4j + 1.6.1 + + + + + + + + + + + + + + + + + + + + + + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-xml-provider + 2.9.6 + + + + + org.apache.httpcomponents + httpclient + 4.5.6 + + + + + commons-fileupload + commons-fileupload + 1.3.3 + + + + + + + + + + + + net.coobird + thumbnailator + 0.4.8 + + + + + com.auth0 + java-jwt + 3.4.1 + + + + + + + + + + + + + + + + + + + + + + + + + maven-compiler-plugin + 3.7.0 + + + 1.8 + 1.8 + UTF-8 + + + + + org.apache.maven.plugins + maven-resources-plugin + 2.6 + + + UTF-8 + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.21.0 + + true + + + + + + \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..ae666b1 --- /dev/null +++ b/readme.md @@ -0,0 +1,108 @@ +# 民警APP java后端 +--- +#### 技术框架 +- 单体应用 +- SSM +- mysql +- token授权模式 + +#### 数据字典 +## qmrz 数据库 + +> 表格清单 + +| 表名 | 排序规则 | 引擎 | 说明 | +| --- | --- | --- | --- | +| [housepeople](readme/db_housepeople.md) | utf8_general_ci | InnoDB | 一房多人主表 | +| [housepeoplerelation](readme/db_housepeoplerelation.md) | utf8_general_ci | InnoDB | 一房多人关系表 | +| [leaveuser](readme/db_leaveuser.md) | utf8_general_ci | InnoDB | 疑似离开人员表 | +| [leaveuserrelation](readme/db_leaveuserrelation.md) | latin1_swedish_ci | InnoDB | 疑似离开人员关系表 | +| [newuser](readme/db_newuser.md) | utf8_general_ci | InnoDB | 新用户入住表 | +| [newuseropentime](readme/db_newuseropentime.md) | utf8_general_ci | InnoDB | 新用户入住开门时间表 | +| [newuserrelation](readme/db_newuserrelation.md) | latin1_swedish_ci | InnoDB | 新用户入住关系表 | +| [people](readme/db_people.md) | utf8_general_ci | InnoDB | 一房多人 人员表 | +| [police](readme/db_police.md) | utf8_general_ci | InnoDB | 民警表,用于帐号登录 | +| [police_belongleader](readme/db_police_belongleader.md) | utf8mb4_0900_ai_ci | InnoDB | 用户归属领导关系 | +| [policearea](readme/db_policearea.md) | utf8mb4_0900_ai_ci | InnoDB | 此表已无效 | +| [policelogin](readme/db_policelogin.md) | latin1_swedish_ci | InnoDB | 用户登录状态,用户登录信息保存到数据库,可扩展缓存中间件,如redis | +| [policezone](readme/db_policezone.md) | utf8mb4_0900_ai_ci | InnoDB | 警员负责区关系表(民警与警务区) | +| [process](readme/db_process.md) | latin1_swedish_ci | InnoDB | 操作日志表 | +| [zoneadmin](readme/db_zoneadmin.md) | utf8mb4_0900_ai_ci | InnoDB | 行政区划编码 | +| [zonepubinfo](readme/db_zonepubinfo.md) | gbk_chinese_ci | InnoDB | 区编码表 | + + + + +#### 接口 +- [接口约定(必看)](readme/interface_lookme.md) + + +- [民警登录](readme/interface_policelogin_login.md) +- [修改密码](readme/interface_police_setpassword.md) +- [民警是否登录](readme/interface_policelogin_islogin.md) +- [警民退出登录](readme/interface_policelogin_logout.md) +- [获取当前登录的民警信息](readme/interface_policelogin_info.md) + + +- [获取民警列表(分页、警务区)](readme/interface_police_list.md) +- [获取民警列表(分页、分派时使用)](readme/interface_police_list_assign.md) +- [警务区保存](readme/interface_policezone_save.md) +- [获取当前登录帐号的已分配到的警务区](readme/interface_policezone_listme.md) + +- [左边树数据](readme/interface_zonepubInfo_sel.md) +- [页面查看详情](readme/interface_procss_sel.md) + +- [新入住人员信息](readme/interface_newuser_selpage.md) +- [新入住人数小红点总数](readme/interface_newuser_cou.md) +- [新入住人员导出](readme/interface_newuser_export.md) +- [新入住人员状态修改](readme/interface_newuserrelation_upd.md) +- [查询最近开门时间](readme/interface_newuseropentime_sel.md) +- [疑似离开人员状态修改](readme/interface_leaveuserrelation_upd.md) +- [疑似离开人员信息](readme/interface_leaveuser_sel.md) +- [疑似离开人员小红点](readme/interface_leaveuser_cou.md) +- [疑似离开人员导出](readme/interface_leaveuser_export.md) +- [新入住和疑似离开流转 ](readme/interface_process_upd.md) +- [一房多人信息](readme/interface_housePeople_sel.md) +- [一房多人具体信息](readme/interface_peoplee_sel.md) +- [一房多人流程流转](readme/interface_missionhousepeople_sel.md) +- [一房多人小红点](readme/interface_missionhousepeople_cou.md) +- [一房多人导出](readme/interface__housePeople_export.md) +- [短期异常活动](readme/inteface_houseabnormal_readme.md) +- [短期异常活动开门记录](readme/inteface_houseabnormalopendoor_readme.md) +- [长期未活动房屋](readme/inteface_houseinactive_readme.md) +- [长期活动开门记录](readme/inteface_houseinactiveopendoor_readme.md) +- [出租房屋表](readme/inteface_houseinfo_readme.md) +- [居住详细信息](readme/inteface_houseinfouser_readme.md) +- [一房多人主表](readme/inteface_housepeople_readme.md) +- [一房多人关系表](readme/inteface_housepeoplerelation_readme.md) +- [访客频繁居住](readme/inteface_housetemporary_readme.md) +- [访客频繁更换房客](readme/inteface_housetemporarytenant_readme.md) +- [访客频繁更换房客具体信息](readme/inteface_housetemporarytenantnews_readme.md) +- [访客频繁居住用户](readme/inteface_housetemporaryuser_readme.md) +- [app使用人信息](readme/inteface_keyapp_readme.md) +- [蓝扣使用人信息表](readme/inteface_keyblue_readme.md) +- [居住房间日志表,流动人员(appuser)或蓝扣(bluekey)](readme/inteface_keyhouse_readme.md) +- [频繁换人](readme/inteface_peopleexchangehouses_readme.md) +- [频繁换人详细信息](readme/inteface_peopleexchangehousesnews_readme.md) +- [一证多房](readme/inteface_peoplemultipleroom_readme.md) +- [一证多房详细信息](readme/inteface_peoplemultipleroomnews_readme.md) +- [夜间频繁活动](readme/inteface_peoplenocturnalactivity_readme.md) +- [夜间频繁活动开门记录](readme/inteface_peoplenocturnalaopendoor_readme.md) +- [人员开门记录信息](readme/inteface_useropendoor_readme.md) +- [开门记录表](readme/inteface_useropendoorrecord_readme.md) + +------------------------ + +- [添加用户](readme/inteface_police_add.md) +- [可选 角色项|职务项](readme/inteface_police_role_job_list.md) +- [可选警务区](readme/inteface_police_zoneall.md) +- [可选所属 所领导|民警](readme/inteface_police_belongleader.md) + +- [修改用户](readme/inteface_police_edit.md) +- [删除用户](readme/inteface_police_del.md) + + +- [http代理](readme/interface_file_proxy.md) + +## [部署说明](readme/release.md) +java -jar --spring.profiles.active=prod