From ab5a12f6bb6e5ad345ef11d64cf2995589bbb4a7 Mon Sep 17 00:00:00 2001 From: lhc Date: Mon, 22 Feb 2021 16:16:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E6=A1=86=E6=9E=B6=E6=95=B4?= =?UTF-8?q?=E5=90=88=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 11 + hcframe-parent/hcframe-base/pom.xml | 187 + .../common/ControllerExceptionHandler.java | 34 + .../java/com/hcframe/base/common/Mapper.java | 15 + .../RestControllerExceptionHandler.java | 21 + .../hcframe/base/common/ResultPageInfo.java | 19 + .../com/hcframe/base/common/ResultVO.java | 155 + .../hcframe/base/common/ServiceException.java | 27 + .../com/hcframe/base/common/WebPageInfo.java | 61 + .../base/common/config/FrameConfig.java | 14 + .../base/common/config/GetHttpSession.java | 22 + .../base/common/config/RedisConfig.java | 36 + .../base/common/config/SimpleCORSFilter.java | 57 + .../base/common/config/SwaggerConfig.java | 86 + .../base/common/config/SwaggerEntity.java | 18 + .../base/common/config/WebMvcConfig.java | 9 + .../common/config/webSessionListener.java | 23 + .../hcframe/base/common/utils/DateUtil.java | 84 + .../base/common/utils/EmptyCheckUtils.java | 15 + .../base/common/utils/EncryptUtil.java | 321 + .../hcframe/base/common/utils/HttpClient.java | 86 + .../base/common/utils/JudgeException.java | 12 + .../hcframe/base/common/utils/ListUtil.java | 23 + .../hcframe/base/common/utils/MD5Util.java | 19 + .../base/common/utils/MailAuthenticator.java | 21 + .../hcframe/base/common/utils/MailBean.java | 98 + .../base/common/utils/MailOperate.java | 142 + .../base/common/utils/MyPageHelper.java | 15 + .../hcframe/base/common/utils/ObjectUtil.java | 133 + .../hcframe/base/common/utils/RandomUtil.java | 18 + .../hcframe/base/common/utils/RedisUtil.java | 584 + .../hcframe/base/common/utils/RegexUtil.java | 11 + .../base/common/utils/SpringContextUtil.java | 30 + .../base/common/utils/StringUtils.java | 417 + .../base/common/utils/TableNameUtil.java | 51 + .../base/common/utils/TokenProccessor.java | 34 + .../base/common/utils/UserInfoUtil.java | 60 + .../hcframe/base/common/utils/XssClass.java | 18 + .../module/auth/constants/AuthConstants.java | 94 + .../controller/AuthFunctionController.java | 44 + .../auth/controller/FtUserController.java | 58 + .../base/module/auth/dao/FtUserDao.java | 14 + .../base/module/auth/dao/OsSysMenuDao.java | 17 + .../base/module/auth/entity/FtUser.java | 74 + .../base/module/auth/entity/OsSysMenu.java | 114 + .../auth/service/AuthFunctionService.java | 5 + .../module/auth/service/FtUserService.java | 18 + .../base/module/auth/service/MenuService.java | 16 + .../service/impl/AuthFunctionServiceImpl.java | 11 + .../auth/service/impl/FtUserServiceImpl.java | 85 + .../auth/service/impl/MenuServiceImpl.java | 206 + .../hcframe/base/module/auth/vo/MetaVo.java | 59 + .../hcframe/base/module/auth/vo/RouterVo.java | 55 + .../base/module/cache/CacheService.java | 22 + .../base/module/cache/base/BaseCache.java | 21 + .../module/cache/base/impl/BaseCacheImpl.java | 62 + .../base/module/cache/emum/CacheType.java | 15 + .../module/cache/impl/DatasourceCache.java | 55 + .../base/module/cache/impl/TableCache.java | 129 + .../module/data/annotation/DataIgnore.java | 18 + .../module/data/constants/FieldConstants.java | 5 + .../module/data/constants/QueryConstants.java | 27 + .../data/controller/IndexController.java | 13 + .../data/controller/TableController.java | 138 + .../base/module/data/dao/TableMapper.java | 47 + .../data/exception/BaseMapperException.java | 23 + .../module/data/exception/SqlException.java | 50 + .../base/module/data/module/BaseMapper.java | 125 + .../module/data/module/BaseMapperImpl.java | 600 + .../base/module/data/module/Condition.java | 432 + .../base/module/data/module/DataMap.java | 460 + .../module/data/module/JoinCondition.java | 26 + .../module/data/module/SelectCondition.java | 340 + .../base/module/data/module/WebCondition.java | 104 + .../module/data/service/TableService.java | 41 + .../data/service/impl/TableServiceImpl.java | 252 + .../datasource/annotation/DatasourceAnno.java | 20 + .../aop/DataSourceAnnoOperation.java | 47 + .../module/datasource/aop/DataSourceAop.java | 63 + .../config/DataSourceConfiguration.java | 92 + .../controller/DataSourceController.java | 105 + .../DatasourceConfigController.java | 44 + .../controller/DatasourceTypeController.java | 31 + .../datasource/dao/DatasourceConfigDao.java | 16 + .../datasource/dao/DatasourceTokenDao.java | 14 + .../datasource/dao/DatasourceTypeDao.java | 15 + .../datasource/dynamic/DBContextHolder.java | 34 + .../dynamic/MyDynamicDataSource.java | 28 + .../datasource/entity/DatasourceConfig.java | 113 + .../datasource/entity/DatasourceToken.java | 31 + .../datasource/entity/DatasourceType.java | 57 + .../datasource/service/DataSourceService.java | 34 + .../service/DatasourceConfigService.java | 15 + .../service/DatasourceTypeService.java | 9 + .../service/impl/DataSourceServiceImpl.java | 286 + .../impl/DatasourceConfigServiceImpl.java | 96 + .../impl/DatasourceTypeServiceImpl.java | 21 + .../datasource/utils/DataSourceUtil.java | 208 + .../module/datasource/utils/DataUnit.java | 18 + .../hcframe/base/module/druid/DruidAuth.java | 12 + .../base/module/druid/DruidConfig.java | 54 + .../hcframe/base/module/shiro/AuthFilter.java | 141 + .../hcframe/base/module/shiro/AuthToken.java | 26 + .../base/module/shiro/CustomRealm.java | 85 + .../hcframe/base/module/shiro/FtToken.java | 42 + .../base/module/shiro/ShiroConfig.java | 83 + .../base/module/shiro/dao/FtTokenDao.java | 16 + .../module/shiro/service/ShiroService.java | 21 + .../shiro/service/ShiroServiceImpl.java | 143 + .../base/module/shiro/service/ShiroType.java | 7 + .../module/shiro/service/SystemRealm.java | 35 + .../controller/TableConfigController.java | 104 + .../controller/TableGenController.java | 65 + .../module/tableconfig/dao/OsSysFieldDao.java | 20 + .../tableconfig/dao/OsSysSelectDao.java | 16 + .../tableconfig/dao/OsSysTableMapper.java | 12 + .../tableconfig/dao/TableGenMapper.java | 68 + .../module/tableconfig/entity/FieldInfo.java | 42 + .../module/tableconfig/entity/OsSysField.java | 80 + .../tableconfig/entity/OsSysSelect.java | 40 + .../module/tableconfig/entity/OsSysTable.java | 36 + .../module/tableconfig/entity/TableInfo.java | 35 + .../service/TableConfigService.java | 36 + .../tableconfig/service/TableGenService.java | 21 + .../service/impl/TableConfigServiceImpl.java | 235 + .../service/impl/TableGenServiceImpl.java | 116 + .../module/tableconfig/sqlinfo/SqlInfo.java | 23 + .../tableconfig/sqlinfo/SqlInfoFactory.java | 46 + .../sqlinfo/impl/MysqlSqlInfo.java | 45 + .../sqlinfo/impl/OracleSqlInfo.java | 45 + .../src/main/resources/logback-spring.xml | 98 + .../resources/mapping/auth/OsSysMenuDao.xml | 57 + .../resources/mapping/data/TableMapper.xml | 167 + .../datasource/DatasourceConfigDao.xml | 22 + .../mapping/datasource/DatasourceTokenDao.xml | 10 + .../mapping/datasource/DatasourceTypeDao.xml | 11 + .../resources/mapping/shiro/FtTokenDao.xml | 11 + .../mapping/tableconfig/OsSysFieldMapper.xml | 27 + .../mapping/tableconfig/OsSysSelectDao.xml | 14 + .../mapping/tableconfig/OsSysTableMapper.xml | 22 + .../mapping/tableconfig/TableGenMapper.xml | 85 + .../src/main/resources/static/favicon.ico | Bin 0 -> 1150 bytes .../src/main/resources/static/favicon1.ico | Bin 0 -> 67646 bytes .../src/main/resources/static/img/head.png | Bin 0 -> 39732 bytes .../img/icons/android-chrome-192x192.png | Bin 0 -> 2484 bytes .../img/icons/android-chrome-512x512.png | Bin 0 -> 7168 bytes .../icons/android-chrome-maskable-192x192.png | Bin 0 -> 69230 bytes .../icons/android-chrome-maskable-512x512.png | Bin 0 -> 1108862 bytes .../img/icons/apple-touch-icon-120x120.png | Bin 0 -> 1536 bytes .../img/icons/apple-touch-icon-152x152.png | Bin 0 -> 1921 bytes .../img/icons/apple-touch-icon-180x180.png | Bin 0 -> 2020 bytes .../img/icons/apple-touch-icon-60x60.png | Bin 0 -> 803 bytes .../img/icons/apple-touch-icon-76x76.png | Bin 0 -> 964 bytes .../static/img/icons/apple-touch-icon.png | Bin 0 -> 2020 bytes .../static/img/icons/favicon-16x16.png | Bin 0 -> 1150 bytes .../static/img/icons/favicon-32x32.png | Bin 0 -> 4418 bytes .../img/icons/msapplication-icon-144x144.png | Bin 0 -> 1947 bytes .../static/img/icons/mstile-150x150.png | Bin 0 -> 1786 bytes .../static/img/icons/safari-pinned-tab.svg | 112 + .../src/main/resources/static/manifest.json | 1 + ...nifest.2fdae813464120215433d93eaa63f80c.js | 442 + .../src/main/resources/static/robots.txt | 2 + .../main/resources/static/service-worker.js | 16 + .../static/static/css/401.e0076f64.css | 1 + .../static/static/css/404.8ad84ff7.css | 1 + .../static/static/css/app.af098992.css | 1 + .../static/css/chunk-3c36ef5f.933e9f93.css | 1 + .../static/static/css/chunk-libs.eaa66087.css | 1 + .../static/static/css/dashboard.27360722.css | 1 + .../static/static/css/icons.b9c551e0.css | 1 + .../static/static/css/login.10e2a281.css | 1 + .../static/static/css/profile.80424d51.css | 1 + .../static/static/fonts/bpmn.08b5f281.eot | Bin 0 -> 47728 bytes .../static/static/fonts/bpmn.3c4c9f45.woff2 | Bin 0 -> 12932 bytes .../static/static/fonts/bpmn.acbc6cbd.woff | Bin 0 -> 15916 bytes .../static/static/fonts/bpmn.f922519e.ttf | Bin 0 -> 47576 bytes .../static/fonts/element-icons.535877f5.woff | Bin 0 -> 28200 bytes .../static/fonts/element-icons.732389de.ttf | Bin 0 -> 55956 bytes .../static/static/img/401.089007e7.gif | Bin 0 -> 164227 bytes .../static/static/img/404-cloud.0f4bc32b.png | Bin 0 -> 4766 bytes .../static/static/img/404.a57b6f31.png | Bin 0 -> 98071 bytes .../static/static/img/404.db18abdc.svg | 3 + .../static/static/img/back-top.65f4922c.svg | 4 + .../static/static/img/bpmn.1381b44e.svg | 224 + .../static/static/img/bug.c1385220.svg | 3 + .../static/static/img/chart.4aceb68d.svg | 3 + .../static/static/img/clipboard.1a29af96.svg | 3 + .../static/static/img/component.85b95edf.svg | 3 + .../static/static/img/connect.3006a2fb.svg | 12 + .../static/static/img/dashboard.7678c0e2.svg | 3 + .../static/img/data-config.c519b269.svg | 10 + .../static/static/img/datasource.c4497db5.svg | 10 + .../static/img/documentation.816b2012.svg | 3 + .../static/static/img/drag.48e0ccc1.svg | 3 + .../static/static/img/druid.b66f2d4f.svg | 10 + .../static/static/img/edit.2f0537d0.svg | 4 + .../static/static/img/education.31d0c153.svg | 3 + .../static/static/img/email.43046cb5.svg | 4 + .../static/static/img/example.58214a86.svg | 3 + .../static/static/img/excel.1b7088fd.svg | 4 + .../static/img/exit-fullscreen.01ba74e4.svg | 3 + .../static/static/img/eye-off.5403cc4b.svg | 3 + .../static/static/img/eye-on.297e1699.svg | 6 + .../static/static/img/field.67d5281f.svg | 10 + .../static/static/img/form.bf349f32.svg | 3 + .../static/static/img/fullscreen.8d5abcf6.svg | 3 + .../static/static/img/func-auth.37f2f0e4.svg | 10 + .../static/static/img/guide-2.2247295d.svg | 3 + .../static/static/img/guide.bb687ef5.svg | 3 + .../static/static/img/hamburger.c165db60.svg | 3 + .../static/static/img/icon.e94dfd43.svg | 3 + .../static/img/international.2bf66df2.svg | 3 + .../static/static/img/language.54a2abc7.svg | 4 + .../static/static/img/like.6da50df8.svg | 3 + .../static/static/img/link.723de906.svg | 5 + .../static/static/img/list.c8b4d416.svg | 3 + .../static/static/img/lock.017ab310.svg | 3 + .../static/static/img/log.92058a83.svg | 10 + .../static/static/img/message.a04029ac.svg | 3 + .../static/static/img/money.45bf45d5.svg | 3 + .../static/static/img/monitor.4a6ae046.svg | 10 + .../static/static/img/nested.07001d4f.svg | 3 + .../static/static/img/password.74c4ccf7.svg | 3 + .../static/static/img/pdf.9cd54e40.svg | 3 + .../static/static/img/people.66b2f058.svg | 3 + .../static/static/img/peoples.427f2fae.svg | 4 + .../static/static/img/qq.44496527.svg | 3 + .../static/static/img/search.7d1db82a.svg | 3 + .../static/static/img/shopping.fee3df90.svg | 3 + .../static/static/img/size.5b470b16.svg | 3 + .../static/static/img/skill.5ab5ef91.svg | 3 + .../static/static/img/star.b8a4c104.svg | 3 + .../static/img/sytem-manage.84963cb9.svg | 10 + .../static/static/img/tab.8b079bad.svg | 3 + .../static/static/img/table.e06c3135.svg | 4 + .../static/static/img/theme.d686b3d7.svg | 3 + .../static/static/img/tree-table.f6d0f376.svg | 3 + .../static/static/img/tree.55adbaf0.svg | 3 + .../static/static/img/user.831f041e.svg | 3 + .../static/static/img/wechat.40233019.svg | 4 + .../static/static/img/workflow.1e377bad.svg | 10 + .../static/static/img/zip.6da3bad1.svg | 3 + .../static/static/js/401.fc1c2e2f.js | 1 + .../static/static/js/404.702eba0c.js | 1 + .../static/static/js/app.3d682d0a.js | 1 + .../static/js/auth-redirect.1242a2aa.js | 1 + .../static/js/chunk-3c36ef5f.00de207f.js | 1 + .../static/js/chunk-5d1c9be8.d45228c7.js | 6 + .../static/js/chunk-898aa520.ba683b5a.js | 1 + .../static/js/chunk-elementUI.191dd9dc.js | 1 + .../static/static/js/chunk-libs.66619e24.js | 79 + .../static/static/js/dashboard.2656a435.js | 1 + .../static/static/js/icons.61e8ebfb.js | 1 + .../static/static/js/login.196cd88a.js | 1 + .../static/static/js/profile.9437ea47.js | 1 + .../static/static/js/redirect.1296a7f4.js | 1 + .../static/static/js/runtime.dd2ba41f.js | 1 + .../resources/static/tinymce/emojis.min.js | 2 + .../main/resources/static/tinymce/langs/es.js | 389 + .../main/resources/static/tinymce/langs/ja.js | 389 + .../resources/static/tinymce/langs/ko_KR.js | 419 + .../resources/static/tinymce/langs/zh_CN.js | 389 + .../tinymce/skins/content.inline.min.css | 8 + .../static/tinymce/skins/content.min.css | 8 + .../tinymce/skins/content.mobile.min.css | 1 + .../tinymce/skins/fonts/tinymce-mobile.woff | Bin 0 -> 4624 bytes .../static/tinymce/skins/skin.min.css | 8 + .../static/tinymce/skins/skin.mobile.min.css | 2 + .../src/main/resources/templates/index.html | 1 + hcframe-parent/hcframe-user/pom.xml | 48 + .../com/hcframe/user/UserApplication.java | 24 + .../common/config/CommandLineRunnerImpl.java | 36 + .../user/common/config/ShiroRealmConfig.java | 80 + .../manage/controller/ManageController.java | 24 + .../controller/ManageDataController.java | 15 + .../manage/service/ManageDataService.java | 4 + .../module/manage/service/ManageService.java | 4 + .../service/impl/ManageServiceDataImpl.java | 23 + .../service/impl/ManageServiceImpl.java | 23 + .../src/main/resources/application.yml | 131 + .../src/main/resources/banner.txt | 25 + .../src/main/resources/datasource.db | Bin 0 -> 77824 bytes .../src/main/resources/ehcache.xml | 71 + hcframe-parent/pom.xml | 39 + hcframe-parent/storage/pom.xml | 203 + .../storage/StorageApplication.java | 16 + .../storage/api/BucketController.java | 58 + .../storage/api/FileController.java | 187 + .../storage/api/RegionController.java | 58 + .../storage/config/SimpleCORSFilter.java | 57 + .../storage/config/Swagger2Configuration.java | 34 + .../storage/config/WebMvcConfig.java | 9 + .../sinoparasoft/storage/domain/Bucket.java | 182 + .../storage/domain/HistoryFile.java | 186 + .../storage/domain/LogicalFile.java | 230 + .../storage/domain/PhysicalFile.java | 205 + .../storage/domain/PhysicalTileFile.java | 250 + .../storage/domain/StorageRegion.java | 223 + .../storage/model/BucketQueryRequest.java | 23 + .../storage/model/DataTableQuery.java | 81 + .../storage/model/FileBlockCreateRequest.java | 105 + .../storage/model/FileCreateRequest.java | 39 + .../storage/model/FileCreateResponse.java | 41 + .../model/LogicalFileQueryRequest.java | 34 + .../sinoparasoft/storage/model/Metadata.java | 87 + .../sinoparasoft/storage/model/Response.java | 28 + .../model/StorageRegionQueryRequest.java | 23 + .../storage/model/UuidCreateResponse.java | 40 + .../storage/repository/BucketRepository.java | 72 + .../repository/HistoryFileRepository.java | 14 + .../repository/LogicalFileRepository.java | 64 + .../repository/PhysicalFileRepository.java | 53 + .../PhysicalTileFileRepository.java | 81 + .../repository/StorageRegionRepository.java | 99 + .../storage/service/BucketService.java | 274 + .../storage/service/FileService.java | 951 ++ .../storage/service/LogicalFileService.java | 5 + .../storage/service/MetadataService.java | 71 + .../storage/service/PhysicalFileService.java | 214 + .../service/PhysicalTileFileService.java | 218 + .../storage/service/StorageRegionService.java | 420 + .../sinoparasoft/storage/utils/CasUtils.java | 242 + .../storage/utils/DigestUtils.java | 127 + .../storage/utils/HttpClientUtils.java | 294 + .../storage/utils/HttpsClientUtils.java | 140 + .../sinoparasoft/storage/utils/MD5Utils.java | 29 + .../storage/utils/StringUtils.java | 31 + .../storage/web/ModelAndViewController.java | 129 + .../src/main/resources/application-iscas.yml | 25 + .../src/main/resources/application.yml | 35 + .../storage/src/main/resources/create-db.sql | 3 + .../storage/src/main/resources/ehcache.xml | 11 + .../storage/src/main/resources/logback.xml | 31 + .../static/casAssets/images/casBack.png | Bin 0 -> 263934 bytes .../static/casAssets/images/casBackBody.png | Bin 0 -> 523233 bytes .../static/casAssets/images/casBackNav.png | Bin 0 -> 26948 bytes .../static/casAssets/images/casLogo.png | Bin 0 -> 4569 bytes .../static/casAssets/images/casTitle.png | Bin 0 -> 7837 bytes .../bootstrap-table/css/bootstrap-table.css | 342 + .../css/bootstrap-table.min.css | 1 + .../bootstrap-table/css/bootstrap.min.css | 6 + .../bootstrap-table/css/bootstrap_bak.min.css | 5 + .../plugins/bootstrap-table/data/data1.json | 108 + .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../fonts/glyphicons-halflings-regular.svg | 288 + .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes .../glyphicons-halflings-regular.eot | Bin 0 -> 20335 bytes .../glyphicons-halflings-regular.svg | 229 + .../glyphicons-halflings-regular.ttf | Bin 0 -> 41280 bytes .../glyphicons-halflings-regular.woff | Bin 0 -> 23320 bytes .../js/bootstrap-table-export.js | 81 + .../js/bootstrap-table-zh-CN.js | 46 + .../bootstrap-table/js/bootstrap-table.js | 3067 ++++ .../js/bootstrap-table_scroll.js | 3196 ++++ .../bootstrap-table/js/bootstrap.min.js | 6 + .../bootstrap-table/js/jquery.base64.js | 190 + .../plugins/bootstrap-table/js/jquery.min.js | 4 + .../plugins/bootstrap-table/js/tableExport.js | 359 + .../plugins/bootstrap/css/bootstrap-theme.css | 587 + .../bootstrap/css/bootstrap-theme.css.map | 1 + .../bootstrap/css/bootstrap-theme.min.css | 6 + .../bootstrap/css/bootstrap-theme.min.css.map | 1 + .../plugins/bootstrap/css/bootstrap.css | 6757 ++++++++ .../plugins/bootstrap/css/bootstrap.css.map | 1 + .../plugins/bootstrap/css/bootstrap.min.css | 6 + .../bootstrap/css/bootstrap.min.css.map | 1 + .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../fonts/glyphicons-halflings-regular.svg | 288 + .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes .../plugins/bootstrap/js/bootstrap.js | 2396 +++ .../plugins/bootstrap/js/bootstrap.min.js | 7 + .../casAssets/plugins/bootstrap/js/npm.js | 13 + .../plugins/jquery/jquery-3.1.0.min.js | 4 + .../jquery.mCustomScrollbar.concat.min.js | 5 + .../scrollbar/jquery.mCustomScrollbar.css | 1268 ++ .../plugins/scrollbar/mCSB_buttons.png | Bin 0 -> 2998 bytes .../casAssets/plugins/scrollbar/style.css | 845 + .../main/resources/static/css/adminlte.css | 13055 ++++++++++++++++ .../resources/static/css/adminlte.css.map | 252 + .../resources/static/css/adminlte.min.css | 11 + .../src/main/resources/static/css/common.css | 1 + .../main/resources/static/fragments/aside.css | 34 + .../main/resources/static/fragments/aside.js | 10 + .../resources/static/fragments/breadcrumb.css | 13 + .../resources/static/fragments/breadcrumb.js | 39 + .../resources/static/fragments/hamburger.css | 15 + .../resources/static/fragments/hamburger.js | 16 + .../static/icomoon/fonts/icomoon.eot | Bin 0 -> 210828 bytes .../static/icomoon/fonts/icomoon.svg | 1346 ++ .../static/icomoon/fonts/icomoon.ttf | Bin 0 -> 210664 bytes .../static/icomoon/fonts/icomoon.woff | Bin 0 -> 210740 bytes .../main/resources/static/icomoon/style.css | 4035 +++++ .../resources/static/img/AdminLTELogo.png | Bin 0 -> 10380 bytes .../src/main/resources/static/img/avatar.png | Bin 0 -> 8543 bytes .../main/resources/static/img/avatar04.png | Bin 0 -> 14037 bytes .../src/main/resources/static/img/avatar2.png | Bin 0 -> 8836 bytes .../src/main/resources/static/img/avatar3.png | Bin 0 -> 9780 bytes .../src/main/resources/static/img/avatar5.png | Bin 0 -> 8007 bytes .../main/resources/static/img/boxed-bg.jpg | Bin 0 -> 123770 bytes .../main/resources/static/img/boxed-bg.png | Bin 0 -> 43694 bytes .../src/main/resources/static/img/casBack.png | Bin 0 -> 263934 bytes .../src/main/resources/static/img/casLogo.png | Bin 0 -> 4569 bytes .../main/resources/static/img/casTitle.png | Bin 0 -> 7837 bytes .../main/resources/static/img/castscsLogo.png | Bin 0 -> 11874 bytes .../static/img/credit/american-express.png | Bin 0 -> 2205 bytes .../resources/static/img/credit/cirrus.png | Bin 0 -> 1593 bytes .../static/img/credit/mastercard.png | Bin 0 -> 1593 bytes .../resources/static/img/credit/mestro.png | Bin 0 -> 1588 bytes .../resources/static/img/credit/paypal.png | Bin 0 -> 2046 bytes .../resources/static/img/credit/paypal2.png | Bin 0 -> 1372 bytes .../main/resources/static/img/credit/visa.png | Bin 0 -> 1137 bytes .../resources/static/img/default-150x150.png | Bin 0 -> 373 bytes .../src/main/resources/static/img/icons.png | Bin 0 -> 1154 bytes .../src/main/resources/static/img/photo1.png | Bin 0 -> 673900 bytes .../src/main/resources/static/img/photo2.png | Bin 0 -> 424395 bytes .../src/main/resources/static/img/photo3.jpg | Bin 0 -> 392079 bytes .../src/main/resources/static/img/photo4.jpg | Bin 0 -> 1179224 bytes .../resources/static/img/user1-128x128.jpg | Bin 0 -> 2879 bytes .../resources/static/img/user2-160x160.jpg | Bin 0 -> 7070 bytes .../resources/static/img/user3-128x128.jpg | Bin 0 -> 3511 bytes .../resources/static/img/user4-128x128.jpg | Bin 0 -> 3477 bytes .../resources/static/img/user5-128x128.jpg | Bin 0 -> 6446 bytes .../resources/static/img/user6-128x128.jpg | Bin 0 -> 4342 bytes .../resources/static/img/user7-128x128.jpg | Bin 0 -> 6434 bytes .../resources/static/img/user8-128x128.jpg | Bin 0 -> 5060 bytes .../resources/static/intro/css/bootstrap.css | 6757 ++++++++ .../static/intro/css/fancybox.custom.css | 227 + .../static/intro/css/font-awesome.css | 2337 +++ .../resources/static/intro/css/icomoon.css | 506 + .../static/intro/css/owl.carousel.css | 71 + .../static/intro/css/owl.carousel.min.css | 13 + .../static/intro/css/owl.transitions.css | 163 + .../resources/static/intro/css/shortcodes.css | 3839 +++++ .../main/resources/static/intro/css/style.css | 179 + .../main/resources/static/intro/favicon.ico | Bin 0 -> 1150 bytes .../intro/fonts/fontawesome-webfont.woff2 | Bin 0 -> 77160 bytes .../resources/static/intro/fonts/icomoon.eot | Bin 0 -> 37196 bytes .../resources/static/intro/fonts/icomoon.svg | 170 + .../resources/static/intro/fonts/icomoon.ttf | Bin 0 -> 37032 bytes .../resources/static/intro/fonts/icomoon.woff | Bin 0 -> 24512 bytes .../static/intro/images/about-bg.jpg | Bin 0 -> 53998 bytes .../resources/static/intro/images/about.jpg | Bin 0 -> 150764 bytes .../static/intro/images/ajaxloader.gif | Bin 0 -> 1517 bytes .../resources/static/intro/images/blank.gif | Bin 0 -> 43 bytes .../resources/static/intro/images/contact.jpg | Bin 0 -> 79144 bytes .../static/intro/images/fancybox.png | Bin 0 -> 14497 bytes .../resources/static/intro/images/grab.cur | Bin 0 -> 326 bytes .../static/intro/images/grey-texture.png | Bin 0 -> 10039 bytes .../static/intro/images/intro-slide01.jpg | Bin 0 -> 100767 bytes .../static/intro/images/intro-slide02.jpg | Bin 0 -> 55727 bytes .../static/intro/images/intro-slide03.jpg | Bin 0 -> 34390 bytes .../static/intro/images/intro-slide04.jpg | Bin 0 -> 63526 bytes .../static/intro/images/news-single.jpg | Bin 0 -> 41638 bytes .../resources/static/intro/images/news.jpg | Bin 0 -> 86525 bytes .../static/intro/images/portfolio-bg.jpg | Bin 0 -> 14840 bytes .../static/intro/images/process-bg.jpg | Bin 0 -> 16188 bytes .../static/intro/images/swipe-icon.png | Bin 0 -> 838 bytes .../static/intro/images/twitter-bg.jpg | Bin 0 -> 12428 bytes .../static/intro/images/work-504-big.jpg | Bin 0 -> 63526 bytes .../intro/images/work-confirmation-big.jpg | Bin 0 -> 56959 bytes .../static/intro/images/work-flat-ui-big.jpg | Bin 0 -> 31369 bytes .../intro/images/work-super-desk-big.jpg | Bin 0 -> 45555 bytes .../intro/images/work-super-wii-big.jpg | Bin 0 -> 27968 bytes .../intro/images/work-super-wii-big2.jpg | Bin 0 -> 30530 bytes .../static/intro/images/work-symbols-big.jpg | Bin 0 -> 34390 bytes .../static/intro/images/work-vinyl-big.jpg | Bin 0 -> 29447 bytes .../static/intro/images/work-workouts-big.jpg | Bin 0 -> 42104 bytes .../static/intro/js/bootstrap.min.js | 7 + .../main/resources/static/intro/js/custom.js | 38 + .../static/intro/js/jquery.easing-1.3.min.js | 38 + .../intro/js/jquery.fancybox-1.3.4.pack.js | 76 + .../static/intro/js/jquery.gmap.min.js | 35 + .../resources/static/intro/js/jquery.min.js | 4 + .../intro/js/jquery.queryloader2.min.js | 15 + .../static/intro/js/jquery.scrollto.min.js | 7 + .../static/intro/js/jquery.small.plugins.js | 66 + .../static/intro/js/jquery.transit.min.js | 1 + .../static/intro/js/modernizr.custom.js | 4 + .../static/intro/js/owl.carousel.min.js | 7 + .../resources/static/intro/js/smoothscroll.js | 9 + .../static/intro/js/waypoints.min.js | 8 + .../static/intro/picture/about-slide01.jpg | Bin 0 -> 41669 bytes .../static/intro/picture/about-slide02.jpg | Bin 0 -> 14490 bytes .../static/intro/picture/business1.png | Bin 0 -> 30913 bytes .../static/intro/picture/business2.png | Bin 0 -> 80599 bytes .../static/intro/picture/business3.png | Bin 0 -> 109920 bytes .../static/intro/picture/business4.png | Bin 0 -> 102705 bytes .../static/intro/picture/business5.png | Bin 0 -> 75687 bytes .../static/intro/picture/business6.png | Bin 0 -> 79368 bytes .../static/intro/picture/business7.png | Bin 0 -> 56071 bytes .../static/intro/picture/business8.png | Bin 0 -> 101226 bytes .../static/intro/picture/business9.png | Bin 0 -> 66715 bytes .../resources/static/intro/picture/cas1.jpg | Bin 0 -> 82293 bytes .../resources/static/intro/picture/cas1.png | Bin 0 -> 34975 bytes .../resources/static/intro/picture/cas2.jpg | Bin 0 -> 133708 bytes .../resources/static/intro/picture/cas2.png | Bin 0 -> 126686 bytes .../static/intro/picture/casLogo.png | Bin 0 -> 4569 bytes .../static/intro/picture/casLogo_white.png | Bin 0 -> 2024 bytes .../static/intro/picture/dataAll.png | Bin 0 -> 1697014 bytes .../static/intro/picture/dataOne.png | Bin 0 -> 169655 bytes .../static/intro/picture/interconnect1.png | Bin 0 -> 34854 bytes .../static/intro/picture/interconnect2.png | Bin 0 -> 42359 bytes .../static/intro/picture/logo-3docean.png | Bin 0 -> 2856 bytes .../static/intro/picture/logo-audiojungle.png | Bin 0 -> 3267 bytes .../static/intro/picture/logo-codecanyon.png | Bin 0 -> 2830 bytes .../intro/picture/logo-graphicriver.png | Bin 0 -> 3035 bytes .../static/intro/picture/logo-photodune.png | Bin 0 -> 3224 bytes .../static/intro/picture/logo-themeforest.png | Bin 0 -> 2986 bytes .../resources/static/intro/picture/logo.png | Bin 0 -> 1344 bytes .../static/intro/picture/member01.jpg | Bin 0 -> 5065 bytes .../static/intro/picture/member02.jpg | Bin 0 -> 6487 bytes .../static/intro/picture/member03.jpg | Bin 0 -> 5543 bytes .../static/intro/picture/member04.jpg | Bin 0 -> 5415 bytes .../static/intro/picture/mobile1.jpg | Bin 0 -> 19378 bytes .../static/intro/picture/mobile2.png | Bin 0 -> 31207 bytes .../static/intro/picture/mobile3.png | Bin 0 -> 156507 bytes .../resources/static/intro/picture/netAd1.png | Bin 0 -> 336886 bytes .../resources/static/intro/picture/netAd2.jpg | Bin 0 -> 19246 bytes .../static/intro/picture/news-image02.jpg | Bin 0 -> 15664 bytes .../static/intro/picture/news-single02.jpg | Bin 0 -> 19314 bytes .../static/intro/picture/process-graph.png | Bin 0 -> 15399 bytes .../static/intro/picture/spectra-logo.png | Bin 0 -> 1216 bytes .../static/intro/picture/work-504.jpg | Bin 0 -> 15445 bytes .../intro/picture/work-confirmation.jpg | Bin 0 -> 16516 bytes .../static/intro/picture/work-flat-ui.jpg | Bin 0 -> 12967 bytes .../static/intro/picture/work-super-desk.jpg | Bin 0 -> 10274 bytes .../static/intro/picture/work-super-wii.jpg | Bin 0 -> 9094 bytes .../static/intro/picture/work-symbols.jpg | Bin 0 -> 8256 bytes .../static/intro/picture/work-vinyl.jpg | Bin 0 -> 15531 bytes .../static/intro/picture/work-workouts.jpg | Bin 0 -> 16968 bytes .../static/intro/picture/xhhyfwxt.png | Bin 0 -> 1081461 bytes .../static/intro/picture/xmsbglxt.png | Bin 0 -> 874444 bytes .../static/intro/picture/zxxtbgxt.png | Bin 0 -> 727125 bytes .../static/intro/picture/电子书首页.png | Bin 0 -> 279610 bytes .../main/resources/static/intro/service.ico | Bin 0 -> 1150 bytes .../src/main/resources/static/js/adminlte.js | 823 + .../main/resources/static/js/adminlte.js.map | 1 + .../main/resources/static/js/adminlte.min.js | 7 + .../resources/static/js/adminlte.min.js.map | 1 + .../resources/static/js/applications/index.js | 263 + .../main/resources/static/js/buckets/index.js | 143 + .../src/main/resources/static/js/demo.js | 199 + .../resources/static/js/files/elupload.js | 49 + .../main/resources/static/js/files/index.js | 145 + .../main/resources/static/js/files/upload.js | 35 + .../main/resources/static/js/flavors/index.js | 165 + .../resources/static/js/identities/index.js | 173 + .../static/js/microservices/index.js | 133 + .../resources/static/js/openstacks/index.js | 127 + .../static/js/organizations/index.js | 284 + .../main/resources/static/js/regions/index.js | 146 + .../main/resources/static/js/roles/index.js | 129 + .../main/resources/static/js/users/index.js | 227 + .../resources/static/js/users/register.js | 39 + .../main/resources/static/js/vue-uploader.js | 2 + .../src/main/resources/templates/about.html | 555 + .../templates/applications/index.html | 220 + .../templates/applications/loginCXQD.html | 21 + .../templates/applications/loginGRHY.html | 20 + .../templates/applications/loginKJQK.html | 33 + .../templates/applications/loginKJST.html | 21 + .../templates/applications/loginNJBC.html | 21 + .../templates/applications/loginNJSW.html | 21 + .../resources/templates/buckets/index.html | 147 + .../src/main/resources/templates/data.html | 314 + .../resources/templates/files/elupload.html | 147 + .../main/resources/templates/files/index.html | 148 + .../resources/templates/files/plupload.html | 147 + .../resources/templates/files/upload.html | 156 + .../resources/templates/flavors/index.html | 156 + .../resources/templates/fragments/aside.html | 71 + .../templates/fragments/breadcrumb.html | 43 + .../templates/fragments/content.html | 66 + .../resources/templates/fragments/footer.html | 25 + .../templates/fragments/hamburger.html | 33 + .../resources/templates/fragments/header.html | 10 + .../resources/templates/fragments/navbar.html | 50 + .../templates/fragments/sidebar.html | 78 + .../resources/templates/identities/index.html | 156 + .../src/main/resources/templates/index.html | 75 + .../main/resources/templates/introduce.html | 153 + .../src/main/resources/templates/layout.html | 52 + .../resources/templates/main-20200319.html | 209 + .../resources/templates/main-20200324.html | 209 + .../src/main/resources/templates/main.html | 137 + .../templates/microservices/index.html | 150 + .../resources/templates/openstacks/index.html | 134 + .../templates/organizations/index.html | 202 + .../resources/templates/regions/index.html | 149 + .../main/resources/templates/roles/index.html | 138 + .../src/main/resources/templates/test.html | 80 + .../main/resources/templates/users/index.html | 159 + .../main/resources/templates/users/login.html | 81 + .../resources/templates/users/register.html | 90 + hcframe-web/.browserslistrc | 2 + hcframe-web/.editorconfig | 35 + hcframe-web/.env.development | 11 + hcframe-web/.env.production | 4 + hcframe-web/.env.staging | 6 + hcframe-web/.eslintignore | 4 + hcframe-web/.eslintrc.js | 53 + hcframe-web/.gitignore | 27 + hcframe-web/LICENSE | 21 + hcframe-web/README-zh.md | 243 + hcframe-web/README.md | 244 + hcframe-web/babel.config.js | 5 + hcframe-web/cypress.json | 3 + hcframe-web/demo/dashboard.png | Bin 0 -> 573068 bytes hcframe-web/jest.config.js | 3 + hcframe-web/mock/api.js | 8 + hcframe-web/mock/api.js.map | 1 + hcframe-web/mock/api.ts | 4 + hcframe-web/mock/articles.js | 112 + hcframe-web/mock/articles.js.map | 1 + hcframe-web/mock/articles.ts | 119 + hcframe-web/mock/mock-server.js | 81 + hcframe-web/mock/mock-server.js.map | 1 + hcframe-web/mock/mock-server.ts | 84 + hcframe-web/mock/role/index.js | 76 + hcframe-web/mock/role/index.js.map | 1 + hcframe-web/mock/role/index.ts | 80 + hcframe-web/mock/role/routes.js | 581 + hcframe-web/mock/role/routes.js.map | 1 + hcframe-web/mock/role/routes.ts | 580 + hcframe-web/mock/security.js | 13 + hcframe-web/mock/security.js.map | 1 + hcframe-web/mock/security.ts | 12 + hcframe-web/mock/swagger.yml | 925 ++ hcframe-web/mock/transactions.js | 25 + hcframe-web/mock/transactions.js.map | 1 + hcframe-web/mock/transactions.ts | 26 + hcframe-web/mock/tsconfig.json | 26 + hcframe-web/mock/users.js | 132 + hcframe-web/mock/users.js.map | 1 + hcframe-web/mock/users.ts | 140 + hcframe-web/package.json | 136 + hcframe-web/postcss.config.js | 5 + hcframe-web/public/favicon.ico | Bin 0 -> 1150 bytes hcframe-web/public/favicon1.ico | Bin 0 -> 67646 bytes hcframe-web/public/img/head.png | Bin 0 -> 39732 bytes .../img/icons/android-chrome-192x192.png | Bin 0 -> 2484 bytes .../img/icons/android-chrome-512x512.png | Bin 0 -> 7168 bytes .../icons/android-chrome-maskable-192x192.png | Bin 0 -> 69230 bytes .../icons/android-chrome-maskable-512x512.png | Bin 0 -> 1108862 bytes .../img/icons/apple-touch-icon-120x120.png | Bin 0 -> 1536 bytes .../img/icons/apple-touch-icon-152x152.png | Bin 0 -> 1921 bytes .../img/icons/apple-touch-icon-180x180.png | Bin 0 -> 2020 bytes .../img/icons/apple-touch-icon-60x60.png | Bin 0 -> 803 bytes .../img/icons/apple-touch-icon-76x76.png | Bin 0 -> 964 bytes .../public/img/icons/apple-touch-icon.png | Bin 0 -> 2020 bytes .../public/img/icons/favicon-16x16.png | Bin 0 -> 1150 bytes .../public/img/icons/favicon-32x32.png | Bin 0 -> 4418 bytes .../img/icons/msapplication-icon-144x144.png | Bin 0 -> 1947 bytes .../public/img/icons/mstile-150x150.png | Bin 0 -> 1786 bytes .../public/img/icons/safari-pinned-tab.svg | 112 + hcframe-web/public/index.html | 17 + hcframe-web/public/manifest.json | 20 + hcframe-web/public/robots.txt | 2 + hcframe-web/public/tinymce/emojis.min.js | 2 + hcframe-web/public/tinymce/langs/es.js | 389 + hcframe-web/public/tinymce/langs/ja.js | 389 + hcframe-web/public/tinymce/langs/ko_KR.js | 419 + hcframe-web/public/tinymce/langs/zh_CN.js | 389 + .../tinymce/skins/content.inline.min.css | 8 + .../public/tinymce/skins/content.min.css | 8 + .../tinymce/skins/content.mobile.min.css | 1 + .../tinymce/skins/fonts/tinymce-mobile.woff | Bin 0 -> 4624 bytes hcframe-web/public/tinymce/skins/skin.min.css | 8 + .../public/tinymce/skins/skin.mobile.min.css | 2 + hcframe-web/src/App.vue | 19 + hcframe-web/src/api/api/CommonApi.ts | 119 + .../src/api/api/activiti/ActivitiApi.ts | 35 + hcframe-web/src/api/api/app/LogApi.ts | 18 + hcframe-web/src/api/api/app/UserApi.ts | 99 + hcframe-web/src/api/api/auth/AuthApi.ts | 18 + .../src/api/api/datasource/DataTypeApi.ts | 18 + .../src/api/api/datasource/DatasourceApi.ts | 99 + .../api/api/datasource/DatasourceStateApi.ts | 34 + .../src/api/api/tablg-config/ConfigApi.ts | 57 + hcframe-web/src/api/articles.ts | 61 + hcframe-web/src/api/mixins/Common.ts | 404 + hcframe-web/src/api/mixins/Datasource.ts | 166 + hcframe-web/src/api/roles.ts | 35 + hcframe-web/src/api/transactions.ts | 8 + hcframe-web/src/api/types.d.ts | 44 + hcframe-web/src/api/users.ts | 54 + .../api/views/commonExample/commonExample.ts | 78 + .../views/config/datasource/datasourceInfo.ts | 228 + .../config/datasource/datasourceState.ts | 109 + .../views/config/table-config/field-config.ts | 238 + .../config/table-config/select-config.ts | 170 + .../views/config/table-config/table-config.ts | 166 + .../system-manage/function-auth/index.ts | 78 + .../system-manage/system-log/system-log.ts | 88 + hcframe-web/src/assets/401-images/401.gif | Bin 0 -> 164227 bytes .../src/assets/404-images/404-cloud.png | Bin 0 -> 4766 bytes hcframe-web/src/assets/404-images/404.png | Bin 0 -> 98071 bytes .../custom-theme/fonts/element-icons.ttf | Bin 0 -> 11028 bytes .../custom-theme/fonts/element-icons.woff | Bin 0 -> 6124 bytes hcframe-web/src/assets/custom-theme/index.css | 1 + hcframe-web/src/clearJS.jar | Bin 0 -> 1944982 bytes hcframe-web/src/common/CommonHttp.ts | 31 + hcframe-web/src/common/CommonLocalAxios.ts | 96 + hcframe-web/src/common/LocalAxios.ts | 96 + hcframe-web/src/common/StringUtils.ts | 39 + hcframe-web/src/common/TimeUtils.ts | 38 + hcframe-web/src/common/Utils.ts | 143 + hcframe-web/src/common/base-loader-data.ts | 61 + hcframe-web/src/common/commonUtil.ts | 90 + hcframe-web/src/common/data/DataModule.ts | 92 + hcframe-web/src/common/data/QueryType.ts | 22 + hcframe-web/src/common/http.ts | 30 + hcframe-web/src/common/promptEnum.ts | 12 + hcframe-web/src/common/requestStatus.ts | 7 + .../src/components/AvatarUpload/index.vue | 78 + .../src/components/BackToTop/index.vue | 111 + hcframe-web/src/components/Bpmn/bpmnView.vue | 54 + .../Bpmn/customTranslate/customTranslate.ts | 21 + .../customTranslate/translationsGerman.ts | 208 + hcframe-web/src/components/Bpmn/index.vue | 393 + .../src/components/Breadcrumb/index.vue | 126 + .../src/components/Charts/BarChart.vue | 136 + .../src/components/Charts/LineChart.vue | 192 + .../src/components/Charts/MixedChart.vue | 248 + .../src/components/Charts/mixins/resize.ts | 67 + .../components/CommonCo/batchUpdateForm.vue | 207 + .../src/components/CommonCo/editTableCo.vue | 311 + hcframe-web/src/components/CommonCo/form.vue | 133 + .../src/components/CommonCo/formCo.vue | 200 + .../src/components/CommonCo/redPointNum.vue | 39 + .../src/components/CommonCo/searchCo.vue | 122 + .../src/components/CommonCo/searchForm.vue | 106 + .../src/components/CommonCo/searchKeyCo.vue | 160 + .../src/components/CommonCo/tableCo.vue | 63 + .../src/components/CommonCo/tableHeadCo.vue | 130 + .../src/components/CommonCo/tableOperaCo.vue | 149 + hcframe-web/src/components/ErrorLog/index.vue | 105 + .../src/components/Hamburger/index.vue | 37 + .../src/components/HeaderSearch/index.vue | 217 + .../src/components/LangSelect/index.vue | 69 + hcframe-web/src/components/PanThumb/index.vue | 124 + .../src/components/RightPanel/index.vue | 151 + .../src/components/Screenfull/index.vue | 51 + .../src/components/SizeSelect/index.vue | 68 + .../src/components/TextHoverEffect/Mallki.vue | 114 + .../src/components/ThemePicker/index.vue | 157 + hcframe-web/src/config.ts | 13 + hcframe-web/src/directives/clipboard/index.ts | 60 + .../directives/el-draggable-dialog/index.ts | 75 + hcframe-web/src/directives/index.ts | 4 + .../src/directives/permission/index.ts | 20 + hcframe-web/src/directives/waves/index.ts | 46 + hcframe-web/src/directives/waves/waves.css | 26 + hcframe-web/src/filters/index.ts | 17 + hcframe-web/src/icons/README.md | 13 + hcframe-web/src/icons/components/404.ts | 12 + hcframe-web/src/icons/components/back-top.ts | 12 + hcframe-web/src/icons/components/bug.ts | 12 + hcframe-web/src/icons/components/chart.ts | 12 + hcframe-web/src/icons/components/clipboard.ts | 12 + hcframe-web/src/icons/components/component.ts | 12 + hcframe-web/src/icons/components/connect.ts | 15 + hcframe-web/src/icons/components/dashboard.ts | 12 + .../src/icons/components/data-config.ts | 12 + .../src/icons/components/datasource.ts | 12 + .../src/icons/components/documentation.ts | 12 + hcframe-web/src/icons/components/drag.ts | 12 + hcframe-web/src/icons/components/druid.ts | 12 + hcframe-web/src/icons/components/edit.ts | 12 + hcframe-web/src/icons/components/education.ts | 12 + hcframe-web/src/icons/components/email.ts | 12 + hcframe-web/src/icons/components/example.ts | 12 + hcframe-web/src/icons/components/excel.ts | 12 + .../src/icons/components/exit-fullscreen.ts | 12 + hcframe-web/src/icons/components/eye-off.ts | 12 + hcframe-web/src/icons/components/eye-on.ts | 12 + hcframe-web/src/icons/components/field.ts | 12 + hcframe-web/src/icons/components/form.ts | 12 + .../src/icons/components/fullscreen.ts | 12 + hcframe-web/src/icons/components/func-auth.ts | 12 + hcframe-web/src/icons/components/guide-2.ts | 12 + hcframe-web/src/icons/components/guide.ts | 12 + hcframe-web/src/icons/components/hamburger.ts | 12 + hcframe-web/src/icons/components/icon.ts | 12 + hcframe-web/src/icons/components/index.ts | 61 + .../src/icons/components/international.ts | 12 + hcframe-web/src/icons/components/language.ts | 12 + hcframe-web/src/icons/components/like.ts | 12 + hcframe-web/src/icons/components/link.ts | 12 + hcframe-web/src/icons/components/list.ts | 12 + hcframe-web/src/icons/components/lock.ts | 12 + hcframe-web/src/icons/components/log.ts | 12 + hcframe-web/src/icons/components/message.ts | 12 + hcframe-web/src/icons/components/money.ts | 12 + hcframe-web/src/icons/components/monitor.ts | 12 + hcframe-web/src/icons/components/nested.ts | 12 + hcframe-web/src/icons/components/password.ts | 12 + hcframe-web/src/icons/components/pdf.ts | 12 + hcframe-web/src/icons/components/people.ts | 12 + hcframe-web/src/icons/components/peoples.ts | 12 + hcframe-web/src/icons/components/qq.ts | 12 + hcframe-web/src/icons/components/search.ts | 12 + hcframe-web/src/icons/components/shopping.ts | 12 + hcframe-web/src/icons/components/size.ts | 12 + hcframe-web/src/icons/components/skill.ts | 12 + hcframe-web/src/icons/components/star.ts | 12 + .../src/icons/components/system-manage.ts | 12 + hcframe-web/src/icons/components/tab.ts | 12 + hcframe-web/src/icons/components/table.ts | 12 + hcframe-web/src/icons/components/theme.ts | 12 + .../src/icons/components/tree-table.ts | 12 + hcframe-web/src/icons/components/tree.ts | 12 + hcframe-web/src/icons/components/user.ts | 12 + hcframe-web/src/icons/components/wechat.ts | 12 + hcframe-web/src/icons/components/workflow.ts | 13 + hcframe-web/src/icons/components/zip.ts | 12 + hcframe-web/src/icons/svg/404.svg | 3 + hcframe-web/src/icons/svg/back-top.svg | 4 + hcframe-web/src/icons/svg/bug.svg | 3 + hcframe-web/src/icons/svg/chart.svg | 3 + hcframe-web/src/icons/svg/clipboard.svg | 3 + hcframe-web/src/icons/svg/component.svg | 3 + hcframe-web/src/icons/svg/connect.svg | 12 + hcframe-web/src/icons/svg/dashboard.svg | 3 + hcframe-web/src/icons/svg/data-config.svg | 10 + hcframe-web/src/icons/svg/datasource.svg | 10 + hcframe-web/src/icons/svg/documentation.svg | 3 + hcframe-web/src/icons/svg/drag.svg | 3 + hcframe-web/src/icons/svg/druid.svg | 10 + hcframe-web/src/icons/svg/edit.svg | 4 + hcframe-web/src/icons/svg/education.svg | 3 + hcframe-web/src/icons/svg/email.svg | 4 + hcframe-web/src/icons/svg/example.svg | 3 + hcframe-web/src/icons/svg/excel.svg | 4 + hcframe-web/src/icons/svg/exit-fullscreen.svg | 3 + hcframe-web/src/icons/svg/eye-off.svg | 3 + hcframe-web/src/icons/svg/eye-on.svg | 6 + hcframe-web/src/icons/svg/field.svg | 10 + hcframe-web/src/icons/svg/form.svg | 3 + hcframe-web/src/icons/svg/fullscreen.svg | 3 + hcframe-web/src/icons/svg/func-auth.svg | 10 + hcframe-web/src/icons/svg/guide-2.svg | 3 + hcframe-web/src/icons/svg/guide.svg | 3 + hcframe-web/src/icons/svg/hamburger.svg | 3 + hcframe-web/src/icons/svg/icon.svg | 3 + hcframe-web/src/icons/svg/international.svg | 3 + hcframe-web/src/icons/svg/language.svg | 4 + hcframe-web/src/icons/svg/like.svg | 3 + hcframe-web/src/icons/svg/link.svg | 5 + hcframe-web/src/icons/svg/list.svg | 3 + hcframe-web/src/icons/svg/lock.svg | 3 + hcframe-web/src/icons/svg/log.svg | 10 + hcframe-web/src/icons/svg/message.svg | 3 + hcframe-web/src/icons/svg/money.svg | 3 + hcframe-web/src/icons/svg/monitor.svg | 10 + hcframe-web/src/icons/svg/nested.svg | 3 + hcframe-web/src/icons/svg/password.svg | 3 + hcframe-web/src/icons/svg/pdf.svg | 3 + hcframe-web/src/icons/svg/people.svg | 3 + hcframe-web/src/icons/svg/peoples.svg | 4 + hcframe-web/src/icons/svg/qq.svg | 3 + hcframe-web/src/icons/svg/search.svg | 3 + hcframe-web/src/icons/svg/shopping.svg | 3 + hcframe-web/src/icons/svg/size.svg | 3 + hcframe-web/src/icons/svg/skill.svg | 3 + hcframe-web/src/icons/svg/star.svg | 3 + hcframe-web/src/icons/svg/sytem-manage.svg | 10 + hcframe-web/src/icons/svg/tab.svg | 3 + hcframe-web/src/icons/svg/table.svg | 4 + hcframe-web/src/icons/svg/theme.svg | 3 + hcframe-web/src/icons/svg/tree-table.svg | 3 + hcframe-web/src/icons/svg/tree.svg | 3 + hcframe-web/src/icons/svg/user.svg | 3 + hcframe-web/src/icons/svg/wechat.svg | 4 + hcframe-web/src/icons/svg/workflow.svg | 10 + hcframe-web/src/icons/svg/zip.svg | 3 + hcframe-web/src/lang/en.ts | 175 + hcframe-web/src/lang/es.ts | 175 + hcframe-web/src/lang/index.ts | 68 + hcframe-web/src/lang/ja.ts | 175 + hcframe-web/src/lang/ko.ts | 175 + hcframe-web/src/lang/zh-modules/activiti.ts | 6 + hcframe-web/src/lang/zh-modules/dtsourceZh.ts | 7 + hcframe-web/src/lang/zh-modules/initdataZh.ts | 7 + .../src/lang/zh-modules/table-config.ts | 8 + hcframe-web/src/lang/zh.ts | 131 + hcframe-web/src/layout/components/AppMain.vue | 57 + .../src/layout/components/Navbar/index.vue | 213 + .../src/layout/components/Settings/index.vue | 125 + .../layout/components/Sidebar/SidebarItem.vue | 203 + .../components/Sidebar/SidebarItemLink.vue | 30 + .../layout/components/Sidebar/SidebarLogo.vue | 112 + .../src/layout/components/Sidebar/index.vue | 138 + .../layout/components/TagsView/ScrollPane.vue | 87 + .../src/layout/components/TagsView/index.vue | 338 + hcframe-web/src/layout/components/index.ts | 5 + hcframe-web/src/layout/index.vue | 172 + hcframe-web/src/layout/mixin/resize.ts | 55 + hcframe-web/src/main.ts | 58 + hcframe-web/src/permission.ts | 76 + .../components/ServiceWorkerUpdatePopup.vue | 67 + .../src/pwa/register-service-worker.ts | 7 + hcframe-web/src/pwa/service-worker.js | 13 + hcframe-web/src/router/index.ts | 147 + hcframe-web/src/settings.ts | 28 + hcframe-web/src/shims.d.ts | 24 + hcframe-web/src/store/index.ts | 24 + hcframe-web/src/store/modules/app.ts | 93 + hcframe-web/src/store/modules/error-log.ts | 40 + hcframe-web/src/store/modules/permission.ts | 82 + hcframe-web/src/store/modules/settings.ts | 40 + hcframe-web/src/store/modules/source-key.ts | 49 + hcframe-web/src/store/modules/tags-view.ts | 141 + hcframe-web/src/store/modules/user.ts | 162 + hcframe-web/src/styles/_mixins.scss | 8 + hcframe-web/src/styles/_svgicon.scss | 31 + hcframe-web/src/styles/_transition.scss | 49 + hcframe-web/src/styles/_variables.scss | 45 + hcframe-web/src/styles/_variables.scss.d.ts | 12 + hcframe-web/src/styles/element-variables.scss | 25 + .../src/styles/element-variables.scss.d.ts | 7 + hcframe-web/src/styles/index.scss | 156 + hcframe-web/src/typings/Base.d.ts | 24 + hcframe-web/src/typings/BaseTable.d.ts | 9 + hcframe-web/src/typings/Table.d.ts | 28 + hcframe-web/src/typings/User.d.ts | 25 + hcframe-web/src/typings/babel-polyfill.d.ts | 1 + .../src/typings/bpmn-js-properties-panel.d.ts | 4 + hcframe-web/src/typings/bpmn-js.d.ts | 2 + .../src/typings/camunda-bpmn-moddle.d.ts | 1 + hcframe-web/src/typings/canvasline.d.ts | 1 + hcframe-web/src/typings/prompt.d.ts | 14 + hcframe-web/src/typings/throttle.d.ts | 1 + .../typings/url-search-params-polyfill.d.ts | 1 + .../src/typings/vue-virtual-scroll-list.d.ts | 4 + .../src/typings/vue-virtual-scroller.d.ts | 1 + hcframe-web/src/typings/vuex-class.d.ts | 1 + hcframe-web/src/utils/clipboard.ts | 30 + hcframe-web/src/utils/cookies.ts | 26 + hcframe-web/src/utils/error-log.ts | 25 + hcframe-web/src/utils/excel.ts | 225 + hcframe-web/src/utils/index.ts | 92 + hcframe-web/src/utils/permission.ts | 15 + hcframe-web/src/utils/request.ts | 72 + hcframe-web/src/utils/scroll-to.ts | 50 + hcframe-web/src/utils/validate.ts | 15 + hcframe-web/src/utils/zip.ts | 21 + .../views/common-example/commonExample.vue | 237 + .../views/config/bpmn-config/bpmnCreate.vue | 88 + .../src/views/config/bpmn-config/bpmnList.vue | 538 + .../views/config/bpmn-config/onlyViewBpmn.vue | 27 + .../config/datasource/components/addCo.vue | 89 + .../config/datasource/components/formCo.vue | 288 + .../config/datasource/components/searchCo.vue | 123 + .../datasource/components/tableHeadCo.vue | 200 + .../config/datasource/datasourceInfo.vue | 191 + .../config/datasource/datasourceInit.vue | 533 + .../config/datasource/datasourceLogin.vue | 302 + .../config/datasource/datasourceState.vue | 148 + hcframe-web/src/views/config/email/email.vue | 73 + .../table-config/components/fieldFormCo.vue | 467 + .../config/table-config/components/formCo.vue | 172 + .../table-config/components/searchCo.vue | 124 + .../table-config/components/searchFieldCo.vue | 248 + .../table-config/components/selectFormCo.vue | 166 + .../table-config/components/tableHeadCo.vue | 273 + .../views/config/table-config/fieldConfig.vue | 190 + .../config/table-config/selectConfig.vue | 163 + .../views/config/table-config/tableConfig.vue | 179 + .../dashboard/admin/components/BarChart.vue | 92 + .../dashboard/admin/components/BoxCard.vue | 137 + .../dashboard/admin/components/LineChart.vue | 121 + .../dashboard/admin/components/PanelGroup.vue | 250 + .../dashboard/admin/components/PieChart.vue | 69 + .../dashboard/admin/components/RadarChart.vue | 104 + .../admin/components/TodoList/Todo.vue | 92 + .../admin/components/TodoList/index.vue | 528 + .../admin/components/TransactionTable.vue | 71 + .../src/views/dashboard/admin/index.vue | 150 + .../src/views/dashboard/editor/index.vue | 91 + hcframe-web/src/views/dashboard/index.vue | 33 + hcframe-web/src/views/error-page/401.vue | 129 + hcframe-web/src/views/error-page/404.vue | 283 + hcframe-web/src/views/icons/element-icons.ts | 74 + hcframe-web/src/views/icons/index.vue | 112 + hcframe-web/src/views/icons/svg-icons.ts | 11 + hcframe-web/src/views/login/auth-redirect.vue | 20 + .../views/login/components/SocialSignin.vue | 87 + hcframe-web/src/views/login/index.vue | 414 + hcframe-web/src/views/monitor/druid/index.vue | 35 + .../src/views/profile/components/Account.vue | 38 + .../src/views/profile/components/Activity.vue | 199 + .../src/views/profile/components/Timeline.vue | 49 + .../src/views/profile/components/UserCard.vue | 148 + hcframe-web/src/views/profile/index.vue | 107 + hcframe-web/src/views/redirect/index.vue | 18 + .../system-manage/function-auth/index.vue | 75 + .../system-manage/system-log/system-log.vue | 106 + hcframe-web/src/views/un-layout/index.vue | 19 + .../tests/unit/components/Breadcrumb.spec.js | 108 + .../unit/components/Breadcrumb.spec.js.map | 1 + .../tests/unit/components/Breadcrumb.spec.ts | 117 + .../tests/unit/utils/parseTime.spec.js | 31 + .../tests/unit/utils/parseTime.spec.js.map | 1 + .../tests/unit/utils/parseTime.spec.ts | 39 + hcframe-web/tests/unit/utils/validate.spec.js | 14 + .../tests/unit/utils/validate.spec.js.map | 1 + hcframe-web/tests/unit/utils/validate.spec.ts | 15 + hcframe-web/tsconfig.json | 41 + hcframe-web/vue.config.js | 113 + 1014 files changed, 109151 insertions(+) create mode 100644 .gitignore create mode 100644 hcframe-parent/hcframe-base/pom.xml create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/ControllerExceptionHandler.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/Mapper.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/RestControllerExceptionHandler.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/ResultPageInfo.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/ResultVO.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/ServiceException.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/WebPageInfo.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/FrameConfig.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/GetHttpSession.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/RedisConfig.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/SimpleCORSFilter.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/SwaggerConfig.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/SwaggerEntity.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/WebMvcConfig.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/webSessionListener.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/DateUtil.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/EmptyCheckUtils.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/EncryptUtil.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/HttpClient.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/JudgeException.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/ListUtil.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MD5Util.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MailAuthenticator.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MailBean.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MailOperate.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MyPageHelper.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/ObjectUtil.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/RandomUtil.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/RedisUtil.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/RegexUtil.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/SpringContextUtil.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/StringUtils.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/TableNameUtil.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/TokenProccessor.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/UserInfoUtil.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/XssClass.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/auth/constants/AuthConstants.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/auth/controller/AuthFunctionController.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/auth/controller/FtUserController.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/auth/dao/FtUserDao.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/auth/dao/OsSysMenuDao.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/auth/entity/FtUser.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/auth/entity/OsSysMenu.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/auth/service/AuthFunctionService.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/auth/service/FtUserService.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/auth/service/MenuService.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/auth/service/impl/AuthFunctionServiceImpl.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/auth/service/impl/FtUserServiceImpl.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/auth/service/impl/MenuServiceImpl.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/auth/vo/MetaVo.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/auth/vo/RouterVo.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/cache/CacheService.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/cache/base/BaseCache.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/cache/base/impl/BaseCacheImpl.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/cache/emum/CacheType.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/cache/impl/DatasourceCache.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/cache/impl/TableCache.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/annotation/DataIgnore.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/constants/FieldConstants.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/constants/QueryConstants.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/controller/IndexController.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/controller/TableController.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/dao/TableMapper.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/exception/BaseMapperException.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/exception/SqlException.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/module/BaseMapper.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/module/BaseMapperImpl.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/module/Condition.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/module/DataMap.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/module/JoinCondition.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/module/SelectCondition.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/module/WebCondition.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/service/TableService.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/data/service/impl/TableServiceImpl.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/annotation/DatasourceAnno.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/aop/DataSourceAnnoOperation.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/aop/DataSourceAop.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/config/DataSourceConfiguration.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/controller/DataSourceController.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/controller/DatasourceConfigController.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/controller/DatasourceTypeController.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/dao/DatasourceConfigDao.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/dao/DatasourceTokenDao.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/dao/DatasourceTypeDao.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/dynamic/DBContextHolder.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/dynamic/MyDynamicDataSource.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/entity/DatasourceConfig.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/entity/DatasourceToken.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/entity/DatasourceType.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/service/DataSourceService.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/service/DatasourceConfigService.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/service/DatasourceTypeService.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/service/impl/DataSourceServiceImpl.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/service/impl/DatasourceConfigServiceImpl.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/service/impl/DatasourceTypeServiceImpl.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/utils/DataSourceUtil.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/datasource/utils/DataUnit.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/druid/DruidAuth.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/druid/DruidConfig.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/shiro/AuthFilter.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/shiro/AuthToken.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/shiro/CustomRealm.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/shiro/FtToken.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/shiro/ShiroConfig.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/shiro/dao/FtTokenDao.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/shiro/service/ShiroService.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/shiro/service/ShiroServiceImpl.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/shiro/service/ShiroType.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/shiro/service/SystemRealm.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/controller/TableConfigController.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/controller/TableGenController.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/dao/OsSysFieldDao.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/dao/OsSysSelectDao.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/dao/OsSysTableMapper.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/dao/TableGenMapper.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/entity/FieldInfo.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/entity/OsSysField.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/entity/OsSysSelect.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/entity/OsSysTable.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/entity/TableInfo.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/service/TableConfigService.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/service/TableGenService.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/service/impl/TableConfigServiceImpl.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/service/impl/TableGenServiceImpl.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/sqlinfo/SqlInfo.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/sqlinfo/SqlInfoFactory.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/sqlinfo/impl/MysqlSqlInfo.java create mode 100644 hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/module/tableconfig/sqlinfo/impl/OracleSqlInfo.java create mode 100644 hcframe-parent/hcframe-base/src/main/resources/logback-spring.xml create mode 100644 hcframe-parent/hcframe-base/src/main/resources/mapping/auth/OsSysMenuDao.xml create mode 100644 hcframe-parent/hcframe-base/src/main/resources/mapping/data/TableMapper.xml create mode 100644 hcframe-parent/hcframe-base/src/main/resources/mapping/datasource/DatasourceConfigDao.xml create mode 100644 hcframe-parent/hcframe-base/src/main/resources/mapping/datasource/DatasourceTokenDao.xml create mode 100644 hcframe-parent/hcframe-base/src/main/resources/mapping/datasource/DatasourceTypeDao.xml create mode 100644 hcframe-parent/hcframe-base/src/main/resources/mapping/shiro/FtTokenDao.xml create mode 100644 hcframe-parent/hcframe-base/src/main/resources/mapping/tableconfig/OsSysFieldMapper.xml create mode 100644 hcframe-parent/hcframe-base/src/main/resources/mapping/tableconfig/OsSysSelectDao.xml create mode 100644 hcframe-parent/hcframe-base/src/main/resources/mapping/tableconfig/OsSysTableMapper.xml create mode 100644 hcframe-parent/hcframe-base/src/main/resources/mapping/tableconfig/TableGenMapper.xml create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/favicon.ico create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/favicon1.ico create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/img/head.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/img/icons/android-chrome-192x192.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/img/icons/android-chrome-512x512.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/img/icons/android-chrome-maskable-192x192.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/img/icons/android-chrome-maskable-512x512.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/img/icons/apple-touch-icon-120x120.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/img/icons/apple-touch-icon-152x152.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/img/icons/apple-touch-icon-180x180.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/img/icons/apple-touch-icon-60x60.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/img/icons/apple-touch-icon-76x76.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/img/icons/apple-touch-icon.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/img/icons/favicon-16x16.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/img/icons/favicon-32x32.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/img/icons/msapplication-icon-144x144.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/img/icons/mstile-150x150.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/img/icons/safari-pinned-tab.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/manifest.json create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/precache-manifest.2fdae813464120215433d93eaa63f80c.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/robots.txt create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/service-worker.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/css/401.e0076f64.css create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/css/404.8ad84ff7.css create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/css/app.af098992.css create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/css/chunk-3c36ef5f.933e9f93.css create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/css/chunk-libs.eaa66087.css create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/css/dashboard.27360722.css create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/css/icons.b9c551e0.css create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/css/login.10e2a281.css create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/css/profile.80424d51.css create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/fonts/bpmn.08b5f281.eot create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/fonts/bpmn.3c4c9f45.woff2 create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/fonts/bpmn.acbc6cbd.woff create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/fonts/bpmn.f922519e.ttf create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/fonts/element-icons.535877f5.woff create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/fonts/element-icons.732389de.ttf create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/401.089007e7.gif create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/404-cloud.0f4bc32b.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/404.a57b6f31.png create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/404.db18abdc.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/back-top.65f4922c.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/bpmn.1381b44e.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/bug.c1385220.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/chart.4aceb68d.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/clipboard.1a29af96.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/component.85b95edf.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/connect.3006a2fb.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/dashboard.7678c0e2.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/data-config.c519b269.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/datasource.c4497db5.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/documentation.816b2012.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/drag.48e0ccc1.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/druid.b66f2d4f.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/edit.2f0537d0.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/education.31d0c153.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/email.43046cb5.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/example.58214a86.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/excel.1b7088fd.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/exit-fullscreen.01ba74e4.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/eye-off.5403cc4b.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/eye-on.297e1699.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/field.67d5281f.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/form.bf349f32.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/fullscreen.8d5abcf6.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/func-auth.37f2f0e4.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/guide-2.2247295d.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/guide.bb687ef5.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/hamburger.c165db60.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/icon.e94dfd43.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/international.2bf66df2.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/language.54a2abc7.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/like.6da50df8.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/link.723de906.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/list.c8b4d416.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/lock.017ab310.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/log.92058a83.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/message.a04029ac.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/money.45bf45d5.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/monitor.4a6ae046.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/nested.07001d4f.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/password.74c4ccf7.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/pdf.9cd54e40.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/people.66b2f058.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/peoples.427f2fae.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/qq.44496527.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/search.7d1db82a.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/shopping.fee3df90.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/size.5b470b16.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/skill.5ab5ef91.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/star.b8a4c104.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/sytem-manage.84963cb9.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/tab.8b079bad.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/table.e06c3135.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/theme.d686b3d7.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/tree-table.f6d0f376.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/tree.55adbaf0.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/user.831f041e.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/wechat.40233019.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/workflow.1e377bad.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/img/zip.6da3bad1.svg create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/js/401.fc1c2e2f.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/js/404.702eba0c.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/js/app.3d682d0a.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/js/auth-redirect.1242a2aa.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/js/chunk-3c36ef5f.00de207f.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/js/chunk-5d1c9be8.d45228c7.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/js/chunk-898aa520.ba683b5a.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/js/chunk-elementUI.191dd9dc.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/js/chunk-libs.66619e24.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/js/dashboard.2656a435.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/js/icons.61e8ebfb.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/js/login.196cd88a.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/js/profile.9437ea47.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/js/redirect.1296a7f4.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/static/js/runtime.dd2ba41f.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/tinymce/emojis.min.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/tinymce/langs/es.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/tinymce/langs/ja.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/tinymce/langs/ko_KR.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/tinymce/langs/zh_CN.js create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/tinymce/skins/content.inline.min.css create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/tinymce/skins/content.min.css create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/tinymce/skins/content.mobile.min.css create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/tinymce/skins/fonts/tinymce-mobile.woff create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/tinymce/skins/skin.min.css create mode 100644 hcframe-parent/hcframe-base/src/main/resources/static/tinymce/skins/skin.mobile.min.css create mode 100644 hcframe-parent/hcframe-base/src/main/resources/templates/index.html create mode 100644 hcframe-parent/hcframe-user/pom.xml create mode 100644 hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/UserApplication.java create mode 100644 hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/common/config/CommandLineRunnerImpl.java create mode 100644 hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/common/config/ShiroRealmConfig.java create mode 100644 hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/controller/ManageController.java create mode 100644 hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/controller/ManageDataController.java create mode 100644 hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/service/ManageDataService.java create mode 100644 hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/service/ManageService.java create mode 100644 hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/service/impl/ManageServiceDataImpl.java create mode 100644 hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/service/impl/ManageServiceImpl.java create mode 100644 hcframe-parent/hcframe-user/src/main/resources/application.yml create mode 100644 hcframe-parent/hcframe-user/src/main/resources/banner.txt create mode 100644 hcframe-parent/hcframe-user/src/main/resources/datasource.db create mode 100644 hcframe-parent/hcframe-user/src/main/resources/ehcache.xml create mode 100644 hcframe-parent/pom.xml create mode 100644 hcframe-parent/storage/pom.xml create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/StorageApplication.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/api/BucketController.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/api/FileController.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/api/RegionController.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/config/SimpleCORSFilter.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/config/Swagger2Configuration.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/config/WebMvcConfig.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/Bucket.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/HistoryFile.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/LogicalFile.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/PhysicalFile.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/PhysicalTileFile.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/StorageRegion.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/BucketQueryRequest.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/DataTableQuery.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/FileBlockCreateRequest.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/FileCreateRequest.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/FileCreateResponse.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/LogicalFileQueryRequest.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/Metadata.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/Response.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/StorageRegionQueryRequest.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/UuidCreateResponse.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/BucketRepository.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/HistoryFileRepository.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/LogicalFileRepository.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/PhysicalFileRepository.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/PhysicalTileFileRepository.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/StorageRegionRepository.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/BucketService.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/FileService.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/LogicalFileService.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/MetadataService.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/PhysicalFileService.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/PhysicalTileFileService.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/StorageRegionService.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/CasUtils.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/DigestUtils.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/HttpClientUtils.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/HttpsClientUtils.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/MD5Utils.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/StringUtils.java create mode 100644 hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/web/ModelAndViewController.java create mode 100644 hcframe-parent/storage/src/main/resources/application-iscas.yml create mode 100644 hcframe-parent/storage/src/main/resources/application.yml create mode 100644 hcframe-parent/storage/src/main/resources/create-db.sql create mode 100644 hcframe-parent/storage/src/main/resources/ehcache.xml create mode 100644 hcframe-parent/storage/src/main/resources/logback.xml create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/images/casBack.png create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/images/casBackBody.png create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/images/casBackNav.png create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/images/casLogo.png create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/images/casTitle.png create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/css/bootstrap-table.css create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/css/bootstrap-table.min.css create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/css/bootstrap.min.css create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/css/bootstrap_bak.min.css create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/data/data1.json create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/fonts/glyphicons-halflings-regular.eot create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/fonts/glyphicons-halflings-regular.svg create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/fonts/glyphicons-halflings-regular.ttf create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/fonts/glyphicons-halflings-regular.woff create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/fonts/glyphicons-halflings-regular.woff2 create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/fonts_bak/glyphicons-halflings-regular.eot create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/fonts_bak/glyphicons-halflings-regular.svg create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/fonts_bak/glyphicons-halflings-regular.ttf create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/fonts_bak/glyphicons-halflings-regular.woff create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/js/bootstrap-table-export.js create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/js/bootstrap-table-zh-CN.js create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/js/bootstrap-table.js create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/js/bootstrap-table_scroll.js create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/js/bootstrap.min.js create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/js/jquery.base64.js create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/js/jquery.min.js create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap-table/js/tableExport.js create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap/css/bootstrap-theme.css create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap/css/bootstrap-theme.css.map create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap/css/bootstrap-theme.min.css create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap/css/bootstrap-theme.min.css.map create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap/css/bootstrap.css create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap/css/bootstrap.css.map create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap/css/bootstrap.min.css create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap/css/bootstrap.min.css.map create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap/fonts/glyphicons-halflings-regular.eot create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap/fonts/glyphicons-halflings-regular.svg create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap/fonts/glyphicons-halflings-regular.ttf create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap/fonts/glyphicons-halflings-regular.woff create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap/fonts/glyphicons-halflings-regular.woff2 create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap/js/bootstrap.js create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap/js/bootstrap.min.js create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/bootstrap/js/npm.js create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/jquery/jquery-3.1.0.min.js create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/scrollbar/jquery.mCustomScrollbar.concat.min.js create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/scrollbar/jquery.mCustomScrollbar.css create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/scrollbar/mCSB_buttons.png create mode 100644 hcframe-parent/storage/src/main/resources/static/casAssets/plugins/scrollbar/style.css create mode 100644 hcframe-parent/storage/src/main/resources/static/css/adminlte.css create mode 100644 hcframe-parent/storage/src/main/resources/static/css/adminlte.css.map create mode 100644 hcframe-parent/storage/src/main/resources/static/css/adminlte.min.css create mode 100644 hcframe-parent/storage/src/main/resources/static/css/common.css create mode 100644 hcframe-parent/storage/src/main/resources/static/fragments/aside.css create mode 100644 hcframe-parent/storage/src/main/resources/static/fragments/aside.js create mode 100644 hcframe-parent/storage/src/main/resources/static/fragments/breadcrumb.css create mode 100644 hcframe-parent/storage/src/main/resources/static/fragments/breadcrumb.js create mode 100644 hcframe-parent/storage/src/main/resources/static/fragments/hamburger.css create mode 100644 hcframe-parent/storage/src/main/resources/static/fragments/hamburger.js create mode 100644 hcframe-parent/storage/src/main/resources/static/icomoon/fonts/icomoon.eot create mode 100644 hcframe-parent/storage/src/main/resources/static/icomoon/fonts/icomoon.svg create mode 100644 hcframe-parent/storage/src/main/resources/static/icomoon/fonts/icomoon.ttf create mode 100644 hcframe-parent/storage/src/main/resources/static/icomoon/fonts/icomoon.woff create mode 100644 hcframe-parent/storage/src/main/resources/static/icomoon/style.css create mode 100644 hcframe-parent/storage/src/main/resources/static/img/AdminLTELogo.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/avatar.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/avatar04.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/avatar2.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/avatar3.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/avatar5.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/boxed-bg.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/img/boxed-bg.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/casBack.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/casLogo.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/casTitle.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/castscsLogo.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/credit/american-express.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/credit/cirrus.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/credit/mastercard.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/credit/mestro.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/credit/paypal.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/credit/paypal2.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/credit/visa.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/default-150x150.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/icons.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/photo1.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/photo2.png create mode 100644 hcframe-parent/storage/src/main/resources/static/img/photo3.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/img/photo4.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/img/user1-128x128.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/img/user2-160x160.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/img/user3-128x128.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/img/user4-128x128.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/img/user5-128x128.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/img/user6-128x128.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/img/user7-128x128.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/img/user8-128x128.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/css/bootstrap.css create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/css/fancybox.custom.css create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/css/font-awesome.css create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/css/icomoon.css create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/css/owl.carousel.css create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/css/owl.carousel.min.css create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/css/owl.transitions.css create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/css/shortcodes.css create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/css/style.css create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/favicon.ico create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/fonts/fontawesome-webfont.woff2 create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/fonts/icomoon.eot create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/fonts/icomoon.svg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/fonts/icomoon.ttf create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/fonts/icomoon.woff create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/about-bg.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/about.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/ajaxloader.gif create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/blank.gif create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/contact.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/fancybox.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/grab.cur create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/grey-texture.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/intro-slide01.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/intro-slide02.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/intro-slide03.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/intro-slide04.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/news-single.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/news.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/portfolio-bg.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/process-bg.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/swipe-icon.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/twitter-bg.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/work-504-big.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/work-confirmation-big.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/work-flat-ui-big.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/work-super-desk-big.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/work-super-wii-big.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/work-super-wii-big2.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/work-symbols-big.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/work-vinyl-big.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/images/work-workouts-big.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/js/bootstrap.min.js create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/js/custom.js create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/js/jquery.easing-1.3.min.js create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/js/jquery.fancybox-1.3.4.pack.js create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/js/jquery.gmap.min.js create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/js/jquery.min.js create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/js/jquery.queryloader2.min.js create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/js/jquery.scrollto.min.js create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/js/jquery.small.plugins.js create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/js/jquery.transit.min.js create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/js/modernizr.custom.js create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/js/owl.carousel.min.js create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/js/smoothscroll.js create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/js/waypoints.min.js create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/about-slide01.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/about-slide02.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/business1.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/business2.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/business3.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/business4.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/business5.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/business6.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/business7.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/business8.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/business9.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/cas1.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/cas1.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/cas2.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/cas2.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/casLogo.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/casLogo_white.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/dataAll.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/dataOne.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/interconnect1.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/interconnect2.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/logo-3docean.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/logo-audiojungle.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/logo-codecanyon.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/logo-graphicriver.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/logo-photodune.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/logo-themeforest.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/logo.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/member01.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/member02.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/member03.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/member04.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/mobile1.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/mobile2.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/mobile3.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/netAd1.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/netAd2.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/news-image02.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/news-single02.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/process-graph.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/spectra-logo.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/work-504.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/work-confirmation.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/work-flat-ui.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/work-super-desk.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/work-super-wii.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/work-symbols.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/work-vinyl.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/work-workouts.jpg create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/xhhyfwxt.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/xmsbglxt.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/zxxtbgxt.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/picture/电子书首页.png create mode 100644 hcframe-parent/storage/src/main/resources/static/intro/service.ico create mode 100644 hcframe-parent/storage/src/main/resources/static/js/adminlte.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/adminlte.js.map create mode 100644 hcframe-parent/storage/src/main/resources/static/js/adminlte.min.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/adminlte.min.js.map create mode 100644 hcframe-parent/storage/src/main/resources/static/js/applications/index.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/buckets/index.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/demo.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/files/elupload.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/files/index.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/files/upload.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/flavors/index.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/identities/index.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/microservices/index.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/openstacks/index.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/organizations/index.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/regions/index.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/roles/index.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/users/index.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/users/register.js create mode 100644 hcframe-parent/storage/src/main/resources/static/js/vue-uploader.js create mode 100644 hcframe-parent/storage/src/main/resources/templates/about.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/applications/index.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/applications/loginCXQD.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/applications/loginGRHY.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/applications/loginKJQK.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/applications/loginKJST.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/applications/loginNJBC.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/applications/loginNJSW.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/buckets/index.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/data.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/files/elupload.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/files/index.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/files/plupload.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/files/upload.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/flavors/index.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/fragments/aside.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/fragments/breadcrumb.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/fragments/content.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/fragments/footer.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/fragments/hamburger.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/fragments/header.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/fragments/navbar.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/fragments/sidebar.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/identities/index.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/index.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/introduce.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/layout.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/main-20200319.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/main-20200324.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/main.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/microservices/index.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/openstacks/index.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/organizations/index.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/regions/index.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/roles/index.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/test.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/users/index.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/users/login.html create mode 100644 hcframe-parent/storage/src/main/resources/templates/users/register.html create mode 100644 hcframe-web/.browserslistrc create mode 100644 hcframe-web/.editorconfig create mode 100644 hcframe-web/.env.development create mode 100644 hcframe-web/.env.production create mode 100644 hcframe-web/.env.staging create mode 100644 hcframe-web/.eslintignore create mode 100644 hcframe-web/.eslintrc.js create mode 100644 hcframe-web/.gitignore create mode 100644 hcframe-web/LICENSE create mode 100644 hcframe-web/README-zh.md create mode 100644 hcframe-web/README.md create mode 100644 hcframe-web/babel.config.js create mode 100644 hcframe-web/cypress.json create mode 100644 hcframe-web/demo/dashboard.png create mode 100644 hcframe-web/jest.config.js create mode 100644 hcframe-web/mock/api.js create mode 100644 hcframe-web/mock/api.js.map create mode 100644 hcframe-web/mock/api.ts create mode 100644 hcframe-web/mock/articles.js create mode 100644 hcframe-web/mock/articles.js.map create mode 100644 hcframe-web/mock/articles.ts create mode 100644 hcframe-web/mock/mock-server.js create mode 100644 hcframe-web/mock/mock-server.js.map create mode 100644 hcframe-web/mock/mock-server.ts create mode 100644 hcframe-web/mock/role/index.js create mode 100644 hcframe-web/mock/role/index.js.map create mode 100644 hcframe-web/mock/role/index.ts create mode 100644 hcframe-web/mock/role/routes.js create mode 100644 hcframe-web/mock/role/routes.js.map create mode 100644 hcframe-web/mock/role/routes.ts create mode 100644 hcframe-web/mock/security.js create mode 100644 hcframe-web/mock/security.js.map create mode 100644 hcframe-web/mock/security.ts create mode 100644 hcframe-web/mock/swagger.yml create mode 100644 hcframe-web/mock/transactions.js create mode 100644 hcframe-web/mock/transactions.js.map create mode 100644 hcframe-web/mock/transactions.ts create mode 100644 hcframe-web/mock/tsconfig.json create mode 100644 hcframe-web/mock/users.js create mode 100644 hcframe-web/mock/users.js.map create mode 100644 hcframe-web/mock/users.ts create mode 100644 hcframe-web/package.json create mode 100644 hcframe-web/postcss.config.js create mode 100644 hcframe-web/public/favicon.ico create mode 100644 hcframe-web/public/favicon1.ico create mode 100644 hcframe-web/public/img/head.png create mode 100644 hcframe-web/public/img/icons/android-chrome-192x192.png create mode 100644 hcframe-web/public/img/icons/android-chrome-512x512.png create mode 100644 hcframe-web/public/img/icons/android-chrome-maskable-192x192.png create mode 100644 hcframe-web/public/img/icons/android-chrome-maskable-512x512.png create mode 100644 hcframe-web/public/img/icons/apple-touch-icon-120x120.png create mode 100644 hcframe-web/public/img/icons/apple-touch-icon-152x152.png create mode 100644 hcframe-web/public/img/icons/apple-touch-icon-180x180.png create mode 100644 hcframe-web/public/img/icons/apple-touch-icon-60x60.png create mode 100644 hcframe-web/public/img/icons/apple-touch-icon-76x76.png create mode 100644 hcframe-web/public/img/icons/apple-touch-icon.png create mode 100644 hcframe-web/public/img/icons/favicon-16x16.png create mode 100644 hcframe-web/public/img/icons/favicon-32x32.png create mode 100644 hcframe-web/public/img/icons/msapplication-icon-144x144.png create mode 100644 hcframe-web/public/img/icons/mstile-150x150.png create mode 100644 hcframe-web/public/img/icons/safari-pinned-tab.svg create mode 100644 hcframe-web/public/index.html create mode 100644 hcframe-web/public/manifest.json create mode 100644 hcframe-web/public/robots.txt create mode 100644 hcframe-web/public/tinymce/emojis.min.js create mode 100644 hcframe-web/public/tinymce/langs/es.js create mode 100644 hcframe-web/public/tinymce/langs/ja.js create mode 100644 hcframe-web/public/tinymce/langs/ko_KR.js create mode 100644 hcframe-web/public/tinymce/langs/zh_CN.js create mode 100644 hcframe-web/public/tinymce/skins/content.inline.min.css create mode 100644 hcframe-web/public/tinymce/skins/content.min.css create mode 100644 hcframe-web/public/tinymce/skins/content.mobile.min.css create mode 100644 hcframe-web/public/tinymce/skins/fonts/tinymce-mobile.woff create mode 100644 hcframe-web/public/tinymce/skins/skin.min.css create mode 100644 hcframe-web/public/tinymce/skins/skin.mobile.min.css create mode 100644 hcframe-web/src/App.vue create mode 100644 hcframe-web/src/api/api/CommonApi.ts create mode 100644 hcframe-web/src/api/api/activiti/ActivitiApi.ts create mode 100644 hcframe-web/src/api/api/app/LogApi.ts create mode 100644 hcframe-web/src/api/api/app/UserApi.ts create mode 100644 hcframe-web/src/api/api/auth/AuthApi.ts create mode 100644 hcframe-web/src/api/api/datasource/DataTypeApi.ts create mode 100644 hcframe-web/src/api/api/datasource/DatasourceApi.ts create mode 100644 hcframe-web/src/api/api/datasource/DatasourceStateApi.ts create mode 100644 hcframe-web/src/api/api/tablg-config/ConfigApi.ts create mode 100644 hcframe-web/src/api/articles.ts create mode 100644 hcframe-web/src/api/mixins/Common.ts create mode 100644 hcframe-web/src/api/mixins/Datasource.ts create mode 100644 hcframe-web/src/api/roles.ts create mode 100644 hcframe-web/src/api/transactions.ts create mode 100644 hcframe-web/src/api/types.d.ts create mode 100644 hcframe-web/src/api/users.ts create mode 100644 hcframe-web/src/api/views/commonExample/commonExample.ts create mode 100644 hcframe-web/src/api/views/config/datasource/datasourceInfo.ts create mode 100644 hcframe-web/src/api/views/config/datasource/datasourceState.ts create mode 100644 hcframe-web/src/api/views/config/table-config/field-config.ts create mode 100644 hcframe-web/src/api/views/config/table-config/select-config.ts create mode 100644 hcframe-web/src/api/views/config/table-config/table-config.ts create mode 100644 hcframe-web/src/api/views/system-manage/function-auth/index.ts create mode 100644 hcframe-web/src/api/views/system-manage/system-log/system-log.ts create mode 100644 hcframe-web/src/assets/401-images/401.gif create mode 100644 hcframe-web/src/assets/404-images/404-cloud.png create mode 100644 hcframe-web/src/assets/404-images/404.png create mode 100644 hcframe-web/src/assets/custom-theme/fonts/element-icons.ttf create mode 100644 hcframe-web/src/assets/custom-theme/fonts/element-icons.woff create mode 100644 hcframe-web/src/assets/custom-theme/index.css create mode 100644 hcframe-web/src/clearJS.jar create mode 100644 hcframe-web/src/common/CommonHttp.ts create mode 100644 hcframe-web/src/common/CommonLocalAxios.ts create mode 100644 hcframe-web/src/common/LocalAxios.ts create mode 100644 hcframe-web/src/common/StringUtils.ts create mode 100644 hcframe-web/src/common/TimeUtils.ts create mode 100644 hcframe-web/src/common/Utils.ts create mode 100644 hcframe-web/src/common/base-loader-data.ts create mode 100644 hcframe-web/src/common/commonUtil.ts create mode 100644 hcframe-web/src/common/data/DataModule.ts create mode 100644 hcframe-web/src/common/data/QueryType.ts create mode 100644 hcframe-web/src/common/http.ts create mode 100644 hcframe-web/src/common/promptEnum.ts create mode 100644 hcframe-web/src/common/requestStatus.ts create mode 100644 hcframe-web/src/components/AvatarUpload/index.vue create mode 100644 hcframe-web/src/components/BackToTop/index.vue create mode 100644 hcframe-web/src/components/Bpmn/bpmnView.vue create mode 100644 hcframe-web/src/components/Bpmn/customTranslate/customTranslate.ts create mode 100644 hcframe-web/src/components/Bpmn/customTranslate/translationsGerman.ts create mode 100644 hcframe-web/src/components/Bpmn/index.vue create mode 100644 hcframe-web/src/components/Breadcrumb/index.vue create mode 100644 hcframe-web/src/components/Charts/BarChart.vue create mode 100644 hcframe-web/src/components/Charts/LineChart.vue create mode 100644 hcframe-web/src/components/Charts/MixedChart.vue create mode 100644 hcframe-web/src/components/Charts/mixins/resize.ts create mode 100644 hcframe-web/src/components/CommonCo/batchUpdateForm.vue create mode 100644 hcframe-web/src/components/CommonCo/editTableCo.vue create mode 100644 hcframe-web/src/components/CommonCo/form.vue create mode 100644 hcframe-web/src/components/CommonCo/formCo.vue create mode 100644 hcframe-web/src/components/CommonCo/redPointNum.vue create mode 100644 hcframe-web/src/components/CommonCo/searchCo.vue create mode 100644 hcframe-web/src/components/CommonCo/searchForm.vue create mode 100644 hcframe-web/src/components/CommonCo/searchKeyCo.vue create mode 100644 hcframe-web/src/components/CommonCo/tableCo.vue create mode 100644 hcframe-web/src/components/CommonCo/tableHeadCo.vue create mode 100644 hcframe-web/src/components/CommonCo/tableOperaCo.vue create mode 100644 hcframe-web/src/components/ErrorLog/index.vue create mode 100644 hcframe-web/src/components/Hamburger/index.vue create mode 100644 hcframe-web/src/components/HeaderSearch/index.vue create mode 100644 hcframe-web/src/components/LangSelect/index.vue create mode 100644 hcframe-web/src/components/PanThumb/index.vue create mode 100644 hcframe-web/src/components/RightPanel/index.vue create mode 100644 hcframe-web/src/components/Screenfull/index.vue create mode 100644 hcframe-web/src/components/SizeSelect/index.vue create mode 100644 hcframe-web/src/components/TextHoverEffect/Mallki.vue create mode 100644 hcframe-web/src/components/ThemePicker/index.vue create mode 100644 hcframe-web/src/config.ts create mode 100644 hcframe-web/src/directives/clipboard/index.ts create mode 100644 hcframe-web/src/directives/el-draggable-dialog/index.ts create mode 100644 hcframe-web/src/directives/index.ts create mode 100644 hcframe-web/src/directives/permission/index.ts create mode 100644 hcframe-web/src/directives/waves/index.ts create mode 100644 hcframe-web/src/directives/waves/waves.css create mode 100644 hcframe-web/src/filters/index.ts create mode 100644 hcframe-web/src/icons/README.md create mode 100644 hcframe-web/src/icons/components/404.ts create mode 100644 hcframe-web/src/icons/components/back-top.ts create mode 100644 hcframe-web/src/icons/components/bug.ts create mode 100644 hcframe-web/src/icons/components/chart.ts create mode 100644 hcframe-web/src/icons/components/clipboard.ts create mode 100644 hcframe-web/src/icons/components/component.ts create mode 100644 hcframe-web/src/icons/components/connect.ts create mode 100644 hcframe-web/src/icons/components/dashboard.ts create mode 100644 hcframe-web/src/icons/components/data-config.ts create mode 100644 hcframe-web/src/icons/components/datasource.ts create mode 100644 hcframe-web/src/icons/components/documentation.ts create mode 100644 hcframe-web/src/icons/components/drag.ts create mode 100644 hcframe-web/src/icons/components/druid.ts create mode 100644 hcframe-web/src/icons/components/edit.ts create mode 100644 hcframe-web/src/icons/components/education.ts create mode 100644 hcframe-web/src/icons/components/email.ts create mode 100644 hcframe-web/src/icons/components/example.ts create mode 100644 hcframe-web/src/icons/components/excel.ts create mode 100644 hcframe-web/src/icons/components/exit-fullscreen.ts create mode 100644 hcframe-web/src/icons/components/eye-off.ts create mode 100644 hcframe-web/src/icons/components/eye-on.ts create mode 100644 hcframe-web/src/icons/components/field.ts create mode 100644 hcframe-web/src/icons/components/form.ts create mode 100644 hcframe-web/src/icons/components/fullscreen.ts create mode 100644 hcframe-web/src/icons/components/func-auth.ts create mode 100644 hcframe-web/src/icons/components/guide-2.ts create mode 100644 hcframe-web/src/icons/components/guide.ts create mode 100644 hcframe-web/src/icons/components/hamburger.ts create mode 100644 hcframe-web/src/icons/components/icon.ts create mode 100644 hcframe-web/src/icons/components/index.ts create mode 100644 hcframe-web/src/icons/components/international.ts create mode 100644 hcframe-web/src/icons/components/language.ts create mode 100644 hcframe-web/src/icons/components/like.ts create mode 100644 hcframe-web/src/icons/components/link.ts create mode 100644 hcframe-web/src/icons/components/list.ts create mode 100644 hcframe-web/src/icons/components/lock.ts create mode 100644 hcframe-web/src/icons/components/log.ts create mode 100644 hcframe-web/src/icons/components/message.ts create mode 100644 hcframe-web/src/icons/components/money.ts create mode 100644 hcframe-web/src/icons/components/monitor.ts create mode 100644 hcframe-web/src/icons/components/nested.ts create mode 100644 hcframe-web/src/icons/components/password.ts create mode 100644 hcframe-web/src/icons/components/pdf.ts create mode 100644 hcframe-web/src/icons/components/people.ts create mode 100644 hcframe-web/src/icons/components/peoples.ts create mode 100644 hcframe-web/src/icons/components/qq.ts create mode 100644 hcframe-web/src/icons/components/search.ts create mode 100644 hcframe-web/src/icons/components/shopping.ts create mode 100644 hcframe-web/src/icons/components/size.ts create mode 100644 hcframe-web/src/icons/components/skill.ts create mode 100644 hcframe-web/src/icons/components/star.ts create mode 100644 hcframe-web/src/icons/components/system-manage.ts create mode 100644 hcframe-web/src/icons/components/tab.ts create mode 100644 hcframe-web/src/icons/components/table.ts create mode 100644 hcframe-web/src/icons/components/theme.ts create mode 100644 hcframe-web/src/icons/components/tree-table.ts create mode 100644 hcframe-web/src/icons/components/tree.ts create mode 100644 hcframe-web/src/icons/components/user.ts create mode 100644 hcframe-web/src/icons/components/wechat.ts create mode 100644 hcframe-web/src/icons/components/workflow.ts create mode 100644 hcframe-web/src/icons/components/zip.ts create mode 100644 hcframe-web/src/icons/svg/404.svg create mode 100644 hcframe-web/src/icons/svg/back-top.svg create mode 100644 hcframe-web/src/icons/svg/bug.svg create mode 100644 hcframe-web/src/icons/svg/chart.svg create mode 100644 hcframe-web/src/icons/svg/clipboard.svg create mode 100644 hcframe-web/src/icons/svg/component.svg create mode 100644 hcframe-web/src/icons/svg/connect.svg create mode 100644 hcframe-web/src/icons/svg/dashboard.svg create mode 100644 hcframe-web/src/icons/svg/data-config.svg create mode 100644 hcframe-web/src/icons/svg/datasource.svg create mode 100644 hcframe-web/src/icons/svg/documentation.svg create mode 100644 hcframe-web/src/icons/svg/drag.svg create mode 100644 hcframe-web/src/icons/svg/druid.svg create mode 100644 hcframe-web/src/icons/svg/edit.svg create mode 100644 hcframe-web/src/icons/svg/education.svg create mode 100644 hcframe-web/src/icons/svg/email.svg create mode 100644 hcframe-web/src/icons/svg/example.svg create mode 100644 hcframe-web/src/icons/svg/excel.svg create mode 100644 hcframe-web/src/icons/svg/exit-fullscreen.svg create mode 100644 hcframe-web/src/icons/svg/eye-off.svg create mode 100644 hcframe-web/src/icons/svg/eye-on.svg create mode 100644 hcframe-web/src/icons/svg/field.svg create mode 100644 hcframe-web/src/icons/svg/form.svg create mode 100644 hcframe-web/src/icons/svg/fullscreen.svg create mode 100644 hcframe-web/src/icons/svg/func-auth.svg create mode 100644 hcframe-web/src/icons/svg/guide-2.svg create mode 100644 hcframe-web/src/icons/svg/guide.svg create mode 100644 hcframe-web/src/icons/svg/hamburger.svg create mode 100644 hcframe-web/src/icons/svg/icon.svg create mode 100644 hcframe-web/src/icons/svg/international.svg create mode 100644 hcframe-web/src/icons/svg/language.svg create mode 100644 hcframe-web/src/icons/svg/like.svg create mode 100644 hcframe-web/src/icons/svg/link.svg create mode 100644 hcframe-web/src/icons/svg/list.svg create mode 100644 hcframe-web/src/icons/svg/lock.svg create mode 100644 hcframe-web/src/icons/svg/log.svg create mode 100644 hcframe-web/src/icons/svg/message.svg create mode 100644 hcframe-web/src/icons/svg/money.svg create mode 100644 hcframe-web/src/icons/svg/monitor.svg create mode 100644 hcframe-web/src/icons/svg/nested.svg create mode 100644 hcframe-web/src/icons/svg/password.svg create mode 100644 hcframe-web/src/icons/svg/pdf.svg create mode 100644 hcframe-web/src/icons/svg/people.svg create mode 100644 hcframe-web/src/icons/svg/peoples.svg create mode 100644 hcframe-web/src/icons/svg/qq.svg create mode 100644 hcframe-web/src/icons/svg/search.svg create mode 100644 hcframe-web/src/icons/svg/shopping.svg create mode 100644 hcframe-web/src/icons/svg/size.svg create mode 100644 hcframe-web/src/icons/svg/skill.svg create mode 100644 hcframe-web/src/icons/svg/star.svg create mode 100644 hcframe-web/src/icons/svg/sytem-manage.svg create mode 100644 hcframe-web/src/icons/svg/tab.svg create mode 100644 hcframe-web/src/icons/svg/table.svg create mode 100644 hcframe-web/src/icons/svg/theme.svg create mode 100644 hcframe-web/src/icons/svg/tree-table.svg create mode 100644 hcframe-web/src/icons/svg/tree.svg create mode 100644 hcframe-web/src/icons/svg/user.svg create mode 100644 hcframe-web/src/icons/svg/wechat.svg create mode 100644 hcframe-web/src/icons/svg/workflow.svg create mode 100644 hcframe-web/src/icons/svg/zip.svg create mode 100644 hcframe-web/src/lang/en.ts create mode 100644 hcframe-web/src/lang/es.ts create mode 100644 hcframe-web/src/lang/index.ts create mode 100644 hcframe-web/src/lang/ja.ts create mode 100644 hcframe-web/src/lang/ko.ts create mode 100644 hcframe-web/src/lang/zh-modules/activiti.ts create mode 100644 hcframe-web/src/lang/zh-modules/dtsourceZh.ts create mode 100644 hcframe-web/src/lang/zh-modules/initdataZh.ts create mode 100644 hcframe-web/src/lang/zh-modules/table-config.ts create mode 100644 hcframe-web/src/lang/zh.ts create mode 100644 hcframe-web/src/layout/components/AppMain.vue create mode 100644 hcframe-web/src/layout/components/Navbar/index.vue create mode 100644 hcframe-web/src/layout/components/Settings/index.vue create mode 100644 hcframe-web/src/layout/components/Sidebar/SidebarItem.vue create mode 100644 hcframe-web/src/layout/components/Sidebar/SidebarItemLink.vue create mode 100644 hcframe-web/src/layout/components/Sidebar/SidebarLogo.vue create mode 100644 hcframe-web/src/layout/components/Sidebar/index.vue create mode 100644 hcframe-web/src/layout/components/TagsView/ScrollPane.vue create mode 100644 hcframe-web/src/layout/components/TagsView/index.vue create mode 100644 hcframe-web/src/layout/components/index.ts create mode 100644 hcframe-web/src/layout/index.vue create mode 100644 hcframe-web/src/layout/mixin/resize.ts create mode 100644 hcframe-web/src/main.ts create mode 100644 hcframe-web/src/permission.ts create mode 100644 hcframe-web/src/pwa/components/ServiceWorkerUpdatePopup.vue create mode 100644 hcframe-web/src/pwa/register-service-worker.ts create mode 100644 hcframe-web/src/pwa/service-worker.js create mode 100644 hcframe-web/src/router/index.ts create mode 100644 hcframe-web/src/settings.ts create mode 100644 hcframe-web/src/shims.d.ts create mode 100644 hcframe-web/src/store/index.ts create mode 100644 hcframe-web/src/store/modules/app.ts create mode 100644 hcframe-web/src/store/modules/error-log.ts create mode 100644 hcframe-web/src/store/modules/permission.ts create mode 100644 hcframe-web/src/store/modules/settings.ts create mode 100644 hcframe-web/src/store/modules/source-key.ts create mode 100644 hcframe-web/src/store/modules/tags-view.ts create mode 100644 hcframe-web/src/store/modules/user.ts create mode 100644 hcframe-web/src/styles/_mixins.scss create mode 100644 hcframe-web/src/styles/_svgicon.scss create mode 100644 hcframe-web/src/styles/_transition.scss create mode 100644 hcframe-web/src/styles/_variables.scss create mode 100644 hcframe-web/src/styles/_variables.scss.d.ts create mode 100644 hcframe-web/src/styles/element-variables.scss create mode 100644 hcframe-web/src/styles/element-variables.scss.d.ts create mode 100644 hcframe-web/src/styles/index.scss create mode 100644 hcframe-web/src/typings/Base.d.ts create mode 100644 hcframe-web/src/typings/BaseTable.d.ts create mode 100644 hcframe-web/src/typings/Table.d.ts create mode 100644 hcframe-web/src/typings/User.d.ts create mode 100644 hcframe-web/src/typings/babel-polyfill.d.ts create mode 100644 hcframe-web/src/typings/bpmn-js-properties-panel.d.ts create mode 100644 hcframe-web/src/typings/bpmn-js.d.ts create mode 100644 hcframe-web/src/typings/camunda-bpmn-moddle.d.ts create mode 100644 hcframe-web/src/typings/canvasline.d.ts create mode 100644 hcframe-web/src/typings/prompt.d.ts create mode 100644 hcframe-web/src/typings/throttle.d.ts create mode 100644 hcframe-web/src/typings/url-search-params-polyfill.d.ts create mode 100644 hcframe-web/src/typings/vue-virtual-scroll-list.d.ts create mode 100644 hcframe-web/src/typings/vue-virtual-scroller.d.ts create mode 100644 hcframe-web/src/typings/vuex-class.d.ts create mode 100644 hcframe-web/src/utils/clipboard.ts create mode 100644 hcframe-web/src/utils/cookies.ts create mode 100644 hcframe-web/src/utils/error-log.ts create mode 100644 hcframe-web/src/utils/excel.ts create mode 100644 hcframe-web/src/utils/index.ts create mode 100644 hcframe-web/src/utils/permission.ts create mode 100644 hcframe-web/src/utils/request.ts create mode 100644 hcframe-web/src/utils/scroll-to.ts create mode 100644 hcframe-web/src/utils/validate.ts create mode 100644 hcframe-web/src/utils/zip.ts create mode 100644 hcframe-web/src/views/common-example/commonExample.vue create mode 100644 hcframe-web/src/views/config/bpmn-config/bpmnCreate.vue create mode 100644 hcframe-web/src/views/config/bpmn-config/bpmnList.vue create mode 100644 hcframe-web/src/views/config/bpmn-config/onlyViewBpmn.vue create mode 100644 hcframe-web/src/views/config/datasource/components/addCo.vue create mode 100644 hcframe-web/src/views/config/datasource/components/formCo.vue create mode 100644 hcframe-web/src/views/config/datasource/components/searchCo.vue create mode 100644 hcframe-web/src/views/config/datasource/components/tableHeadCo.vue create mode 100644 hcframe-web/src/views/config/datasource/datasourceInfo.vue create mode 100644 hcframe-web/src/views/config/datasource/datasourceInit.vue create mode 100644 hcframe-web/src/views/config/datasource/datasourceLogin.vue create mode 100644 hcframe-web/src/views/config/datasource/datasourceState.vue create mode 100644 hcframe-web/src/views/config/email/email.vue create mode 100644 hcframe-web/src/views/config/table-config/components/fieldFormCo.vue create mode 100644 hcframe-web/src/views/config/table-config/components/formCo.vue create mode 100644 hcframe-web/src/views/config/table-config/components/searchCo.vue create mode 100644 hcframe-web/src/views/config/table-config/components/searchFieldCo.vue create mode 100644 hcframe-web/src/views/config/table-config/components/selectFormCo.vue create mode 100644 hcframe-web/src/views/config/table-config/components/tableHeadCo.vue create mode 100644 hcframe-web/src/views/config/table-config/fieldConfig.vue create mode 100644 hcframe-web/src/views/config/table-config/selectConfig.vue create mode 100644 hcframe-web/src/views/config/table-config/tableConfig.vue create mode 100644 hcframe-web/src/views/dashboard/admin/components/BarChart.vue create mode 100644 hcframe-web/src/views/dashboard/admin/components/BoxCard.vue create mode 100644 hcframe-web/src/views/dashboard/admin/components/LineChart.vue create mode 100644 hcframe-web/src/views/dashboard/admin/components/PanelGroup.vue create mode 100644 hcframe-web/src/views/dashboard/admin/components/PieChart.vue create mode 100644 hcframe-web/src/views/dashboard/admin/components/RadarChart.vue create mode 100644 hcframe-web/src/views/dashboard/admin/components/TodoList/Todo.vue create mode 100644 hcframe-web/src/views/dashboard/admin/components/TodoList/index.vue create mode 100644 hcframe-web/src/views/dashboard/admin/components/TransactionTable.vue create mode 100644 hcframe-web/src/views/dashboard/admin/index.vue create mode 100644 hcframe-web/src/views/dashboard/editor/index.vue create mode 100644 hcframe-web/src/views/dashboard/index.vue create mode 100644 hcframe-web/src/views/error-page/401.vue create mode 100644 hcframe-web/src/views/error-page/404.vue create mode 100644 hcframe-web/src/views/icons/element-icons.ts create mode 100644 hcframe-web/src/views/icons/index.vue create mode 100644 hcframe-web/src/views/icons/svg-icons.ts create mode 100644 hcframe-web/src/views/login/auth-redirect.vue create mode 100644 hcframe-web/src/views/login/components/SocialSignin.vue create mode 100644 hcframe-web/src/views/login/index.vue create mode 100644 hcframe-web/src/views/monitor/druid/index.vue create mode 100644 hcframe-web/src/views/profile/components/Account.vue create mode 100644 hcframe-web/src/views/profile/components/Activity.vue create mode 100644 hcframe-web/src/views/profile/components/Timeline.vue create mode 100644 hcframe-web/src/views/profile/components/UserCard.vue create mode 100644 hcframe-web/src/views/profile/index.vue create mode 100644 hcframe-web/src/views/redirect/index.vue create mode 100644 hcframe-web/src/views/system-manage/function-auth/index.vue create mode 100644 hcframe-web/src/views/system-manage/system-log/system-log.vue create mode 100644 hcframe-web/src/views/un-layout/index.vue create mode 100644 hcframe-web/tests/unit/components/Breadcrumb.spec.js create mode 100644 hcframe-web/tests/unit/components/Breadcrumb.spec.js.map create mode 100644 hcframe-web/tests/unit/components/Breadcrumb.spec.ts create mode 100644 hcframe-web/tests/unit/utils/parseTime.spec.js create mode 100644 hcframe-web/tests/unit/utils/parseTime.spec.js.map create mode 100644 hcframe-web/tests/unit/utils/parseTime.spec.ts create mode 100644 hcframe-web/tests/unit/utils/validate.spec.js create mode 100644 hcframe-web/tests/unit/utils/validate.spec.js.map create mode 100644 hcframe-web/tests/unit/utils/validate.spec.ts create mode 100644 hcframe-web/tsconfig.json create mode 100644 hcframe-web/vue.config.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2d74fba --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +## ide +**/.idea +*.iml + +## backend +**/target +**/logs +**/log + +## front +**/*.lock diff --git a/hcframe-parent/hcframe-base/pom.xml b/hcframe-parent/hcframe-base/pom.xml new file mode 100644 index 0000000..4adb817 --- /dev/null +++ b/hcframe-parent/hcframe-base/pom.xml @@ -0,0 +1,187 @@ + + + + parent + com.hcframe + 1.0-SNAPSHOT + + 4.0.0 + + hcframe-base + 1.2.1-SNAPSHOT + + + 8 + 8 + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.1.4 + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + mysql + mysql-connector-java + runtime + + + org.projectlombok + lombok + + + org.springframework.boot + spring-boot-starter-tomcat + provided + + + org.aspectj + aspectjrt + 1.8.0 + + + org.aspectj + aspectjweaver + + + com.alibaba + fastjson + 1.2.70 + + + com.github.xiaoymin + knife4j-spring-boot-starter + 2.0.2 + + + + javax.validation + validation-api + 2.0.1.Final + + + org.apache.shiro + shiro-spring + 1.3.2 + + + org.apache.commons + commons-lang3 + 3.10 + + + commons-io + commons-io + 2.6 + + + javax.mail + mail + 1.4.7 + + + tk.mybatis + mapper-spring-boot-starter + 2.1.5 + + + com.alibaba + druid-spring-boot-starter + 1.2.4 + + + com.github.pagehelper + pagehelper-spring-boot-starter + 1.2.13 + + + org.apache.commons + commons-pool2 + 2.6.2 + + + commons-codec + commons-codec + 1.14 + + + com.google.guava + guava + 25.1-jre + + + + org.xerial + sqlite-jdbc + 3.32.3.2 + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + org.springframework.boot + spring-boot-starter-cache + + + + net.sf.ehcache + ehcache + + + com.dm + Dm7JdbcDriver + 1.8 + + + com.oracle + ojdbc6 + 11.2.0.4 + + + + hcframe-base + + + + + + + + + + + diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/ControllerExceptionHandler.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/ControllerExceptionHandler.java new file mode 100644 index 0000000..a9839e4 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/ControllerExceptionHandler.java @@ -0,0 +1,34 @@ +package com.hcframe.base.common; + +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authz.AuthorizationException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; + +/*** + * @description 异常信息拦截类,如果程序运行过程中抛出异常,会将异常拦截下来,并返回前端一个包含异常信息的Json数据 + */ + +@ControllerAdvice +public class ControllerExceptionHandler { + + @ExceptionHandler(Exception.class) + @ResponseBody + public ResultVO handleServiceException( + Exception e) { + if (e instanceof AuthorizationException) { + return ResultVO.getNoAuthorization(); + } else if (e instanceof AuthenticationException) { + return ResultVO.getFailed("用户名或密码错误"); + } else if (e instanceof RuntimeException) { + System.out.println("handleServiceException"); + e.printStackTrace(); + //封装错误信息 + return ResultVO.getException(e); + } else { + return ResultVO.getException(e); + } + } + //....... +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/Mapper.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/Mapper.java new file mode 100644 index 0000000..b26d356 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/Mapper.java @@ -0,0 +1,15 @@ +package com.hcframe.base.common; + +import tk.mybatis.mapper.common.*; + +/*** + * @description 调用tkmapper进行接口封装 + * @param + */ +public interface Mapper extends + BaseMapper, + ExampleMapper, + RowBoundsMapper, + Marker, ConditionMapper, tk.mybatis.mapper.common.Mapper { + +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/RestControllerExceptionHandler.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/RestControllerExceptionHandler.java new file mode 100644 index 0000000..92aeceb --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/RestControllerExceptionHandler.java @@ -0,0 +1,21 @@ +package com.hcframe.base.common; + +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/*** + * @description 异常信息拦截类,如果程序运行过程中抛出异常,会将异常拦截下来,并返回前端一个包含异常信息的Json数据 + */ + +@RestControllerAdvice +public class RestControllerExceptionHandler { + + @ExceptionHandler(Exception.class) + public ResultVO handleServiceException( + RuntimeException e){ + e.printStackTrace(); + //封装错误信息 + return ResultVO.getException(e); + } + //....... +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/ResultPageInfo.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/ResultPageInfo.java new file mode 100644 index 0000000..7bc0fe1 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/ResultPageInfo.java @@ -0,0 +1,19 @@ +package com.hcframe.base.common; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Builder(toBuilder = true) +@Data +public class ResultPageInfo { + + private List list; + + private long total; +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/ResultVO.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/ResultVO.java new file mode 100644 index 0000000..5824256 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/ResultVO.java @@ -0,0 +1,155 @@ +package com.hcframe.base.common; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.annotations.ApiModelProperty; + +/** + * @author lhc + * @description 返回结果VO对象 + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ResultVO { + + private static final Integer SUCCESS = 0; + private static final Integer FAILED = 1; + private static final Integer ERROR = 2; + private static final Integer UNLOG = 3; + private static final Integer NOAUTH = 4; + //("状态码 0成功 1失败 2服务器出错 3未登录 4没有权限") + private Integer code=SUCCESS; + + //("返回信息") + @ApiModelProperty(example="ActionOK") + private String msg; + + //("返回数据") + private T data; + + private ResultVO() { + this.code = SUCCESS; + this.msg = "Action OK"; + } + private ResultVO(T data) { + this.code = SUCCESS; + this.msg = "Action OK"; + this.data = data; + } + + private ResultVO(Integer code, String msg) { + this.code = code; + this.msg = msg; + } + + private ResultVO(Integer code, String msg, T data) { + this.code = code; + this.msg = msg; + this.data = data; + } + + private ResultVO(Throwable exp){ + this.code=ERROR; + this.msg=exp.getMessage(); + } + /** + * 请求成功 状态码 1 + * + * @param 类型 + * @return ResultVO + */ + public static ResultVO getSuccess(T data) { + return new ResultVO<>(data); + } + /** + * 请求成功 状态码 1 + * + * @param 类型 + * @return ResultVO + */ + public static ResultVO getSuccess() { + return new ResultVO<>(); + } + /** + * 请求成功 状态码 1 + * + * @param msg 返回信息 + * @param data 返回对象 + * @param 类型 + * @return ResultVO + */ + public static ResultVO getSuccess(String msg, T data) { + return new ResultVO(SUCCESS, msg, data); + } + + /** + * 请求失败 状态码 0 + * + * @param msg 返回信息 + * @param 类型 + * @return ResultVO + */ + public static ResultVO getFailed(String msg) { + return new ResultVO<>(FAILED, msg); + } + + /** + * 请求失败 状态 0 + * + * @param msg 返回信息 + * @param data 返回数据 + * @param 类型 + * @return ResultVO + */ + public static ResultVO getFailed(String msg, T data) { + return new ResultVO<>(FAILED, msg, data); + } + + + /** + * 用户未登录 + * + * @param 类型 + * @return ResultVO + */ + public static ResultVO getNoLogin() { + return new ResultVO(UNLOG, "用户未登录,请重新登录"); + } + + + /** + * 用户没有操作权限 + * + * @param 类型 + * @return ResultVO + */ + public static ResultVO getNoAuthorization() { + return new ResultVO(NOAUTH, "用户没有操作权限,请重新登录"); + } + + public static ResultVO getException(Throwable exp) { + return new ResultVO(exp); + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/ServiceException.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/ServiceException.java new file mode 100644 index 0000000..0da6eea --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/ServiceException.java @@ -0,0 +1,27 @@ +package com.hcframe.base.common; + +/*** + * @description 自定义异常类 + */ +public class ServiceException extends RuntimeException { + + public ServiceException() { + + } + + public ServiceException(String message) { + super(message); + } + + public ServiceException(String message, Throwable cause) { + super(message, cause); + } + + public ServiceException(Throwable cause) { + super(cause); + } + + public ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/WebPageInfo.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/WebPageInfo.java new file mode 100644 index 0000000..4f49c72 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/WebPageInfo.java @@ -0,0 +1,61 @@ +package com.hcframe.base.common; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +import java.io.Serializable; + +/** + * (WebPageInfo)实体类 + * + * @author lhc + * @since 2020-02-11 19:29:10 + */ +@NoArgsConstructor +@AllArgsConstructor +@Builder(toBuilder = true) +@Data +@ApiModel +public class WebPageInfo implements Serializable { + + private static final long serialVersionUID = 1156251348750279606L; + + public static final String DESC = "desc"; + public static final String ASC = "asc"; + + @ApiModelProperty( + value="每页显示条数" , + example="10", + dataType = "Integer" + ) + private Integer pageSize = 10; + + @ApiModelProperty( + value="页码" , + example="1", + dataType = "Integer" + ) + private Integer pageNum = 1; + + @ApiModelProperty(value="排序字段") + private String sortField; + + @ApiModelProperty( + value = "正序倒序", + allowableValues = "asc,desc", + example = "asc") + private String order = ASC; + + public static boolean hasSort(WebPageInfo webPageInfo) { + return !StringUtils.isBlank(webPageInfo.getSortField()); + } + + public String getSortSql() { + return this.sortField + " " + this.order; + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/FrameConfig.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/FrameConfig.java new file mode 100644 index 0000000..02fc2e5 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/FrameConfig.java @@ -0,0 +1,14 @@ +package com.hcframe.base.common.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Data +@Component +@ConfigurationProperties(prefix = "frame") +public class FrameConfig { + private Boolean isRedisLogin = false; + private Integer loginTimeout = 4; + private Boolean showControllerLog = true; +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/GetHttpSession.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/GetHttpSession.java new file mode 100644 index 0000000..667d0eb --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/GetHttpSession.java @@ -0,0 +1,22 @@ +package com.hcframe.base.common.config; + +import javax.servlet.http.HttpSession; +import javax.websocket.HandshakeResponse; +import javax.websocket.server.HandshakeRequest; +import javax.websocket.server.ServerEndpointConfig; +import javax.websocket.server.ServerEndpointConfig.Configurator; +/* + * 获取HttpSession + * + */ + +public class GetHttpSession extends Configurator { + + @Override + public void modifyHandshake(ServerEndpointConfig sec, + HandshakeRequest request, HandshakeResponse response) { + HttpSession httpSession=(HttpSession) request.getHttpSession(); + sec.getUserProperties().put(HttpSession.class.getName(),httpSession); + } + +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/RedisConfig.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/RedisConfig.java new file mode 100644 index 0000000..b2f0632 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/RedisConfig.java @@ -0,0 +1,36 @@ +package com.hcframe.base.common.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * @description redis配置类 + * @author lhc + * @date 2020-06-15 + */ +@Configuration +public class RedisConfig { + + /** + * springboot2.x 使用LettuceConnectionFactory 代替 RedisConnectionFactory + * application.yml配置基本信息后,springboot2.x RedisAutoConfiguration能够自动装配 + * LettuceConnectionFactory 和 RedisConnectionFactory 及其 RedisTemplate + * @param redisConnectionFactory + * @return + */ + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){ + RedisTemplate redisTemplate = new RedisTemplate(); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); + redisTemplate.setConnectionFactory(redisConnectionFactory); + return redisTemplate; + } + +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/SimpleCORSFilter.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/SimpleCORSFilter.java new file mode 100644 index 0000000..aa8df9e --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/SimpleCORSFilter.java @@ -0,0 +1,57 @@ +package com.hcframe.base.common.config; + +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.servlet.*; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 跨域支持 + + */ +@WebFilter +@Component +@Order(Ordered.HIGHEST_PRECEDENCE) +public class SimpleCORSFilter implements Filter { + + @Override + public void destroy() { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + /*String[] whiteList = {"http://fwh.castscs.org.cn", "http://localhost"}; + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + String myOrigin = httpServletRequest.getHeader("origin"); + boolean isValid = false; + for( String ip : whiteList ) { + if( myOrigin != null && myOrigin.equals(ip) ){ + isValid = true; + break; + } + }*/ + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + String myOrigin = httpServletRequest.getHeader("origin"); + HttpServletResponse httpServletResponse = (HttpServletResponse) response; + httpServletResponse.setHeader("Access-Control-Allow-Origin", myOrigin); + httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT"); + httpServletResponse.setHeader("Access-Control-Max-Age", "3600"); + httpServletResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with, X-Access-Token, datasource-Key"); + // 是否支持cookie跨域 + httpServletResponse.addHeader("Access-Control-Allow-Credentials", "true"); + chain.doFilter(request, response); + } + + @Override + public void init(FilterConfig arg0) throws ServletException { + + } + +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/SwaggerConfig.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/SwaggerConfig.java new file mode 100644 index 0000000..1432742 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/SwaggerConfig.java @@ -0,0 +1,86 @@ +package com.hcframe.base.common.config; + +import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; +import com.github.xiaoymin.knife4j.spring.filter.SecurityBasicAuthFilter; +import io.swagger.annotations.Api; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; +import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@Configuration +@EnableSwagger2 +@EnableKnife4j +@Import(BeanValidatorPluginsConfiguration.class) +public class SwaggerConfig extends WebMvcConfigurationSupport { + + + @Bean + @ConfigurationProperties(prefix = "swagger") + public SwaggerEntity getSwaggerEntity() { + return new SwaggerEntity(); + } + + @Bean + public Docket createRestApi() { + SwaggerEntity swaggerEntity = getSwaggerEntity(); + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .select() + .apis(RequestHandlerSelectors.withClassAnnotation(Api.class)) + .paths(PathSelectors.any()) + .build(); + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("通用后台模板") + .description("简单优雅的restfun风格") + .termsOfServiceUrl("") + .version("1.0") + .build(); + } + + /** + * 防止@EnableMvc把默认的静态资源路径覆盖了,手动设置的方式 + * + * @param registry + */ + @Override + protected void addResourceHandlers(ResourceHandlerRegistry registry) { + // 解决静态资源无法访问 + registry.addResourceHandler("/**").addResourceLocations("classpath:/static/"); + // 解决swagger无法访问 + registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); + // 解决swagger的js文件无法访问 + registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); + registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/"); + + } + + @Bean + public FilterRegistrationBean SwaggerFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(new SecurityBasicAuthFilter()); + registration.addUrlPatterns("/*"); + registration.setName("swaggerSecurityBasic"); + SwaggerEntity swaggerEntity = getSwaggerEntity(); + registration.addInitParameter("enableBasicAuth",swaggerEntity.enableAuth); + if (SwaggerEntity.TRUE.equals(swaggerEntity.enableAuth)) { + registration.addInitParameter("userName",swaggerEntity.username); + registration.addInitParameter("password",swaggerEntity.password); + } + return registration; + } + +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/SwaggerEntity.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/SwaggerEntity.java new file mode 100644 index 0000000..71d900d --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/SwaggerEntity.java @@ -0,0 +1,18 @@ +package com.hcframe.base.common.config; + +import lombok.Data; + +@Data +public class SwaggerEntity { + + public static final String TRUE = "true"; + public static final String FALSE = "false"; + + public String path; + + public String enableAuth = FALSE; + + public String username = "admin"; + + public String password = "123456"; +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/WebMvcConfig.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/WebMvcConfig.java new file mode 100644 index 0000000..a2ba0bd --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/WebMvcConfig.java @@ -0,0 +1,9 @@ +package com.hcframe.base.common.config; + +import org.springframework.stereotype.Component; +import org.springframework.web.filter.FormContentFilter; + +@Component +public class WebMvcConfig extends FormContentFilter { + +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/webSessionListener.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/webSessionListener.java new file mode 100644 index 0000000..78c55ff --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/config/webSessionListener.java @@ -0,0 +1,23 @@ +package com.hcframe.base.common.config; + +import javax.servlet.ServletRequestEvent; +import javax.servlet.ServletRequestListener; +import javax.servlet.annotation.WebListener; +import javax.servlet.http.HttpServletRequest; + +@WebListener +public class webSessionListener implements ServletRequestListener { + + @Override + public void requestInitialized(ServletRequestEvent sre) { + //将所有request请求都携带上httpSession + ((HttpServletRequest) sre.getServletRequest()).getSession(); + + } + public webSessionListener() { + } + + @Override + public void requestDestroyed(ServletRequestEvent arg0) { + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/DateUtil.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/DateUtil.java new file mode 100644 index 0000000..1e020ff --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/DateUtil.java @@ -0,0 +1,84 @@ +package com.hcframe.base.common.utils; + +import java.time.*; +import java.time.format.DateTimeFormatter; +import java.util.Calendar; +import java.util.Date; + +public class DateUtil { + + + /** + * 日期格式化成字符串 + * @param date + * @param format + * @return + */ + public static String DateFormat(Date date,String format) { + DateTimeFormatter dtf = DateTimeFormatter.ofPattern(format); + LocalDateTime date1 = date2LocalDateTime(date); + return date1.format(dtf); + } + + /** + * 字符串格式化成日期 + */ + public static Date StringFormat(String string,String format) { + DateTimeFormatter dtf = DateTimeFormatter.ofPattern(format); + LocalDate localDate = LocalDate.parse(string,dtf); + return localDate2Date(localDate); + } + + + /** + * Date转换为LocalDateTime + * @param date + */ + public static LocalDateTime date2LocalDateTime(Date date){ + Instant instant = date.toInstant();//An instantaneous point on the time-line.(时间线上的一个瞬时点。) + ZoneId zoneId = ZoneId.systemDefault();//A time-zone ID, such as {@code Europe/Paris}.(时区) + return instant.atZone(zoneId).toLocalDateTime(); + } + + /** + * LocalDateTime转换为Date + * @param localDateTime + */ + public static Date localDateTime2Date( LocalDateTime localDateTime){ + ZoneId zoneId = ZoneId.systemDefault(); + ZonedDateTime zdt = localDateTime.atZone(zoneId);//Combines this date-time with a time-zone to create a ZonedDateTime. + return Date.from(zdt.toInstant()); + } + + /** + * localDate转Date + */ + public static Date localDate2Date(LocalDate localDate) { + ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault()); + Instant instant1 = zonedDateTime.toInstant(); + return Date.from(instant1); + } + + /** + * Date 转 localDate + */ + public static LocalDate date2LocalDate(Date date) { + Instant instant = date.toInstant(); + ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault()); + return zdt.toLocalDate(); + } + + /** + * 获取字符串中的月份 + * @param str + * @param format + * @return + */ + public static int getStringMonth(String str,String format) { + Date date=StringFormat(str, format); + Calendar cal=Calendar.getInstance(); + cal.setTime(date); + return cal.get(Calendar.MONTH); + } + +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/EmptyCheckUtils.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/EmptyCheckUtils.java new file mode 100644 index 0000000..0d6df88 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/EmptyCheckUtils.java @@ -0,0 +1,15 @@ +package com.hcframe.base.common.utils; + +import com.hcframe.base.common.ServiceException; +import org.springframework.util.StringUtils; + +public class EmptyCheckUtils { + + public static boolean checkWithException(Object object,String info){ + if (StringUtils.isEmpty(object)) { + throw new ServiceException(info); + } else { + return true; + } + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/EncryptUtil.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/EncryptUtil.java new file mode 100644 index 0000000..7e1fa0a --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/EncryptUtil.java @@ -0,0 +1,321 @@ +package com.hcframe.base.common.utils; + + +import org.apache.shiro.codec.Base64; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.security.MessageDigest; +import java.security.SecureRandom; + +public class EncryptUtil { + public static final String MD5 = "MD5"; + public static final String SHA1 = "SHA1"; + public static final String HmacMD5 = "HmacMD5"; + public static final String HmacSHA1 = "HmacSHA1"; + public static final String DES = "DES"; + public static final String AES = "AES"; + + /** + * 编码格式;默认使用uft-8 + */ + public String charset = "utf-8"; + /** + * DES + */ + public int keysizeDES = 0; + /** + * AES + */ + public int keysizeAES = 128; + + public static EncryptUtil me; + + private EncryptUtil() { + //单例 + } + + //双重锁 + public static EncryptUtil getInstance() { + if (me == null) { + synchronized (EncryptUtil.class) { + if (me == null) { + me = new EncryptUtil(); + } + } + } + return me; + } + + /** + * 使用MessageDigest进行单向加密(无密码) + * + * @param res 被加密的文本 + * @param algorithm 加密算法名称 + * @return + */ + private String messageDigest(String res, String algorithm) { + try { + MessageDigest md = MessageDigest.getInstance(algorithm); + byte[] resBytes = charset == null ? res.getBytes() : res.getBytes(charset); + return base64(md.digest(resBytes)); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 使用KeyGenerator进行单向/双向加密(可设密码) + * + * @param res 被加密的原文 + * @param algorithm 加密使用的算法名称 + * @param key 加密使用的秘钥 + * @return + */ + private String keyGeneratorMac(String res, String algorithm, String key) { + try { + SecretKey sk = null; + if (key == null) { + KeyGenerator kg = KeyGenerator.getInstance(algorithm); + sk = kg.generateKey(); + } else { + byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset); + sk = new SecretKeySpec(keyBytes, algorithm); + } + Mac mac = Mac.getInstance(algorithm); + mac.init(sk); + byte[] result = mac.doFinal(res.getBytes()); + return base64(result); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 使用KeyGenerator双向加密,DES/AES,注意这里转化为字符串的时候是将2进制转为16进制格式的字符串,不是直接转,因为会出错 + * + * @param res 加密的原文 + * @param algorithm 加密使用的算法名称 + * @param key 加密的秘钥 + * @param keysize + * @param isEncode + * @return + */ + private String keyGeneratorES(String res, String algorithm, String key, int keysize, boolean isEncode) { + try { + KeyGenerator kg = KeyGenerator.getInstance(algorithm); + if (keysize == 0) { + byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset); + kg.init(new SecureRandom(keyBytes)); + } else if (key == null) { + kg.init(keysize); + } else { + byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset); + SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); + secureRandom.setSeed(keyBytes); + kg.init(keysize, secureRandom); + } + SecretKey sk = kg.generateKey(); + SecretKeySpec sks = new SecretKeySpec(sk.getEncoded(), algorithm); + Cipher cipher = Cipher.getInstance(algorithm); + if (isEncode) { + cipher.init(Cipher.ENCRYPT_MODE, sks); + byte[] resBytes = charset == null ? res.getBytes() : res.getBytes(charset); + return parseByte2HexStr(cipher.doFinal(resBytes)); + } else { + cipher.init(Cipher.DECRYPT_MODE, sks); + return new String(cipher.doFinal(parseHexStr2Byte(res))); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + private String base64(byte[] res) { + return new String(Base64.encode(res)); + } + + /** + * 将二进制转换成16进制 + */ + public static String parseByte2HexStr(byte buf[]) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < buf.length; i++) { + String hex = Integer.toHexString(buf[i] & 0xFF); + if (hex.length() == 1) { + hex = '0' + hex; + } + sb.append(hex.toUpperCase()); + } + return sb.toString(); + } + + /** + * 将16进制转换为二进制 + */ + public static byte[] parseHexStr2Byte(String hexStr) { + if (hexStr.length() < 1) { + return null; + } + byte[] result = new byte[hexStr.length() / 2]; + for (int i = 0; i < hexStr.length() / 2; i++) { + int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); + int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); + result[i] = (byte) (high * 16 + low); + } + return result; + } + + /** + * md5加密算法进行加密(不可逆) + * + * @param res 需要加密的原文 + * @return + */ + public String MD5(String res) { + return messageDigest(res, MD5); + } + + /** + * md5加密算法进行加密(不可逆) + * + * @param res 需要加密的原文 + * @param key 秘钥 + * @return + */ + public String MD5(String res, String key) { + return keyGeneratorMac(res, HmacMD5, key); + } + + /** + * 使用SHA1加密算法进行加密(不可逆) + * + * @param res 需要加密的原文 + * @return + */ + public String SHA1(String res) { + return messageDigest(res, SHA1); + } + + /** + * 使用SHA1加密算法进行加密(不可逆) + * + * @param res 需要加密的原文 + * @param key 秘钥 + * @return + */ + public String SHA1(String res, String key) { + return keyGeneratorMac(res, HmacSHA1, key); + } + + /** + * 使用DES加密算法进行加密(可逆) + * + * @param res 需要加密的原文 + * @param key 秘钥 + * @return + */ + public String DESencode(String res, String key) { + return keyGeneratorES(res, DES, key, keysizeDES, true); + } + + /** + * 对使用DES加密算法的密文进行解密(可逆) + * + * @param res 需要解密的密文 + * @param key 秘钥 + * @return + */ + public String DESdecode(String res, String key) { + return keyGeneratorES(res, DES, key, keysizeDES, false); + } + + /** + * 使用AES加密算法经行加密(可逆) + * + * @param res 需要加密的密文 + * @param key 秘钥 + * @return + */ + public String AESencode(String res, String key) { + return keyGeneratorES(res, AES, key, keysizeAES, true); + } + + /** + * 对使用AES加密算法的密文进行解密 + * + * @param res 需要解密的密文 + * @param key 秘钥 + * @return + */ + public String AESdecode(String res, String key) { + return keyGeneratorES(res, AES, key, keysizeAES, false); + } + + /** + * 使用异或进行加密 + * + * @param res 需要加密的密文 + * @param key 秘钥 + * @return + */ + public String XORencode(String res, String key) { + byte[] bs = res.getBytes(); + for (int i = 0; i < bs.length; i++) { + bs[i] = (byte) ((bs[i]) ^ key.hashCode()); + } + return parseByte2HexStr(bs); + } + + /** + * 使用异或进行解密 + * + * @param res 需要解密的密文 + * @param key 秘钥 + * @return + */ + public String XORdecode(String res, String key) { + byte[] bs = parseHexStr2Byte(res); + for (int i = 0; i < bs.length; i++) { + bs[i] = (byte) ((bs[i]) ^ key.hashCode()); + } + return new String(bs); + } + + /** + * 直接使用异或(第一调用加密,第二次调用解密) + * + * @param res 密文 + * @param key 秘钥 + * @return + */ + public int XOR(int res, String key) { + return res ^ key.hashCode(); + } + + /** + * 使用Base64进行加密 + * + * @param res 密文 + * @return + */ + public String Base64Encode(String res) { + return String.valueOf(Base64.encode(res.getBytes())); + } + + /** + * 使用Base64进行解密 + * + * @param res + * @return + */ + public String Base64Decode(String res) { + return new String(Base64.decode(res)); + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/HttpClient.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/HttpClient.java new file mode 100644 index 0000000..f5edf75 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/HttpClient.java @@ -0,0 +1,86 @@ +package com.hcframe.base.common.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + +import java.util.HashMap; +import java.util.Map; + +public class HttpClient { + + + //连接超时时间 + private static final int CONNECTION_TIME_OUT = 30000; + + //读取超时时间 + private static final int READ_TIME_OUT = 30000; + + /** + * post方法接口 + * @param targetUrl---访问的接口网址 + * @param map----携带的参数 + * @return + */ + public static Map postMethod(String targetUrl, Map map){ + //兑换带ticket的url + String urlPath = targetUrl; + // 发送请求 + JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(map)); + JSONArray jsonArray1 = new JSONArray(); + Map map2 = HttpClient.getCasUtils(jsonObject, jsonArray1, ""); + RestTemplate restTemplate = (RestTemplate) map2.get("restTemplate"); + HttpEntity httprequest = (HttpEntity) map2.get("httprequest"); + String response = restTemplate.postForObject(urlPath, httprequest, String.class); + JSONObject jsonObject1 = JSON.parseObject(response); + Map resultMap = JSONObject.toJavaObject(jsonObject1, Map.class); + return resultMap; + } + + /** + * get方法 + * @param targetUrl---目标地址 + * @param itemMap----传入参数 + * @return + */ + public static Map getMethod(String targetUrl,Map itemMap){ + String url = targetUrl; + JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(itemMap)); + JSONArray jsonArray = new JSONArray(); + Map map = HttpClient.getCasUtils(jsonObject,jsonArray,""); + RestTemplate restTemplate = (RestTemplate) map.get("restTemplate"); + String response=restTemplate.getForEntity(url,String.class).getBody(); + JSONObject result = JSON.parseObject(response); + Map resultMap = JSONObject.toJavaObject(result, Map.class); + return resultMap; + } + + public static Map getCasUtils(JSONObject jsonObject, JSONArray jsonArray, String str){ + SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); + requestFactory.setConnectTimeout(CONNECTION_TIME_OUT); + requestFactory.setReadTimeout(READ_TIME_OUT); + RestTemplate restTemplate = new RestTemplate(requestFactory); + // 参数 + HttpHeaders headers = new HttpHeaders(); + MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8"); + headers.setContentType(type); + headers.add("Accept", MediaType.APPLICATION_JSON.toString()); + HttpEntity httprequest= null; + if (jsonObject.isEmpty()&&!jsonArray.isEmpty()) { + httprequest = new HttpEntity(jsonArray.toJSONString(), headers); + } else if (jsonArray.isEmpty() && !jsonObject.isEmpty()) { + httprequest = new HttpEntity(jsonObject.toJSONString(), headers); + } else { + httprequest = new HttpEntity(str, headers); + } + Map map = new HashMap<>(); + map.put("restTemplate", restTemplate); + map.put("httprequest", httprequest); + return map; + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/JudgeException.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/JudgeException.java new file mode 100644 index 0000000..31fb5ef --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/JudgeException.java @@ -0,0 +1,12 @@ +package com.hcframe.base.common.utils; + +import com.hcframe.base.common.ServiceException; + +public class JudgeException { + + public static void isNull(Object o, String msg) { + if (o == null) { + throw new ServiceException(msg); + } + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/ListUtil.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/ListUtil.java new file mode 100644 index 0000000..bf16301 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/ListUtil.java @@ -0,0 +1,23 @@ +package com.hcframe.base.common.utils; + + +import com.hcframe.base.common.ServiceException; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class ListUtil { + + public static Map getValue(String value, List> list,String key) { + Optional> objectMap = list + .stream() + .filter(r -> (Integer) r.get(key) == Integer.parseInt(value)) + .findFirst(); + if (objectMap.isPresent()) { + return objectMap.get(); + } else { + throw new ServiceException("key值不存在"); + } + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MD5Util.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MD5Util.java new file mode 100644 index 0000000..b92adba --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MD5Util.java @@ -0,0 +1,19 @@ +package com.hcframe.base.common.utils; + +import org.springframework.util.DigestUtils; + +public class MD5Util { + + public static String setMd5(String password){ + return DigestUtils.md5DigestAsHex(password.getBytes()); + } + + public static boolean isEqual(String password, String md5) { + String str = DigestUtils.md5DigestAsHex(password.getBytes()); + if (md5.equals(str)) { + return true; + } else { + return false; + } + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MailAuthenticator.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MailAuthenticator.java new file mode 100644 index 0000000..dfd8fde --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MailAuthenticator.java @@ -0,0 +1,21 @@ +package com.hcframe.base.common.utils; + +import javax.mail.Authenticator; +import javax.mail.PasswordAuthentication; + +public class MailAuthenticator extends Authenticator{ + String userName=null; + String password=null; + + public MailAuthenticator(){ + } + public MailAuthenticator(String username, String password) { + this.userName = username; + this.password = password; + } + @Override + protected PasswordAuthentication getPasswordAuthentication(){ + return new PasswordAuthentication(userName, password); + } + +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MailBean.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MailBean.java new file mode 100644 index 0000000..d60bf25 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MailBean.java @@ -0,0 +1,98 @@ +package com.hcframe.base.common.utils; + +import java.util.List; +import java.util.Properties; + +public class MailBean { + // 发送邮件的服务器的IP和端口 + private String mailServerHost; + private String mailServerPort = "25"; + // 邮件发送者的地址 + private String fromAddress; + // 邮件接收者的地址 + private List toAddress; + // 登陆邮件发送服务器的用户名和密码 + private String userName; + private String password; + // 是否需要身份验证 + private boolean validate = false; + // 邮件主题 + private String subject; + // 邮件的文本内容 + private String content; + // 邮件附件的文件名 + private List attachFileNames; + /** + * 获得邮件会话属性 + */ + + public Properties getProperties(){ + Properties p = new Properties(); + p.put("mail.smtp.host", this.mailServerHost); + p.put("mail.smtp.port", this.mailServerPort); + p.put("mail.smtp.auth", validate ? "true" : "false"); + p.put("mail.mime.address.strict", "false"); + return p; + } + public String getMailServerHost() { + return mailServerHost; + } + public void setMailServerHost(String mailServerHost) { + this.mailServerHost = mailServerHost; + } + public String getMailServerPort() { + return mailServerPort; + } + public void setMailServerPort(String mailServerPort) { + this.mailServerPort = mailServerPort; + } + public String getFromAddress() { + return fromAddress; + } + public void setFromAddress(String fromAddress) { + this.fromAddress = fromAddress; + } + + public List getToAddress() { + return toAddress; + } + public void setToAddress(List toAddress) { + this.toAddress = toAddress; + } + public String getUserName() { + return userName; + } + public void setUserName(String userName) { + this.userName = userName; + } + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } + public boolean isValidate() { + return validate; + } + public void setValidate(boolean validate) { + this.validate = validate; + } + public String getSubject() { + return subject; + } + public void setSubject(String subject) { + this.subject = subject; + } + public String getContent() { + return content; + } + public void setContent(String content) { + this.content = content; + } + public List getAttachFileNames() { + return attachFileNames; + } + public void setAttachFileNames(List attachFileNames) { + this.attachFileNames = attachFileNames; + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MailOperate.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MailOperate.java new file mode 100644 index 0000000..674244e --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MailOperate.java @@ -0,0 +1,142 @@ +package com.hcframe.base.common.utils; + + +import javax.activation.DataHandler; +import javax.activation.FileDataSource; +import javax.mail.*; +import javax.mail.internet.*; +import java.io.UnsupportedEncodingException; +import java.util.Date; +import java.util.List; +import java.util.Properties; + +public class MailOperate { + /** + * 以文本格式发送邮件 + * @param mailInfo 待发送的邮件的信息 + */ + public boolean sendTextMail(MailBean mailInfo) { + // 判断是否需要身份认证 + MailAuthenticator authenticator = null; + Properties pro = mailInfo.getProperties(); + if (mailInfo.isValidate()) { + // 如果需要身份认证,则创建一个密码验证器 + authenticator = new MailAuthenticator(mailInfo.getUserName(), mailInfo.getPassword()); + } + // 根据邮件会话属性和密码验证器构造一个发送邮件的session + Session sendMailSession = Session.getDefaultInstance(pro,authenticator); + try { + // 根据session创建一个邮件消息 + Message mailMessage = new MimeMessage(sendMailSession); + // 创建邮件发送者地址 + Address from = new InternetAddress(mailInfo.getFromAddress()); + // 设置邮件消息的发送者 + mailMessage.setFrom(from); + // 创建邮件的接收者地址,并设置到邮件消息中 + List toAddress=null; + if(mailInfo.getToAddress().size()>1){ + toAddress=mailInfo.getToAddress(); + Address[] address =new InternetAddress[toAddress.size()]; + for (int i = 0; i < toAddress.size(); i++) { + address[i]=new InternetAddress(toAddress.get(i)); + } + mailMessage.setRecipients(Message.RecipientType.TO,address); + }else{ + toAddress=mailInfo.getToAddress(); + Address to = new InternetAddress(toAddress.get(0)); + // Message.RecipientType.TO属性表示接收者的类型为TO + mailMessage.setRecipient(Message.RecipientType.TO,to); + } + // 设置邮件消息的主题 + mailMessage.setSubject(mailInfo.getSubject()); + // 设置邮件消息发送的时间 + mailMessage.setSentDate(new Date()); + // 设置邮件消息的主要内容 + String mailContent = mailInfo.getContent(); + mailMessage.setText(mailContent); + // 发送邮件 + Transport.send(mailMessage); + return true; + } catch (MessagingException ex) { +// ex.printStackTrace(); + return false; + } +// return false; + } + + /** + * 以HTML格式发送邮件 + * @param mailInfo 待发送的邮件信息 + * @throws UnsupportedEncodingException + */ + public static boolean sendHtmlMail(MailBean mailInfo) throws UnsupportedEncodingException{ + // 判断是否需要身份认证 + MailAuthenticator authenticator = null; + Properties pro = mailInfo.getProperties(); + //如果需要身份认证,则创建一个密码验证器 + if (mailInfo.isValidate()) { + authenticator = new MailAuthenticator(mailInfo.getUserName(), mailInfo.getPassword()); + } + // 根据邮件会话属性和密码验证器构造一个发送邮件的session + Session sendMailSession = Session.getInstance(pro,authenticator); + + try { + // 根据session创建一个邮件消息 + Message mailMessage = new MimeMessage(sendMailSession); + // 创建邮件发送者地址 + Address from = new InternetAddress(mailInfo.getFromAddress()); + // 设置邮件消息的发送者 + mailMessage.setFrom(from); + // 创建邮件的接收者地址,并设置到邮件消息中 + List toAddress=null; + if(mailInfo.getToAddress().size()>1){ + toAddress=mailInfo.getToAddress(); + Address[] address =new InternetAddress[toAddress.size()]; + for (int i = 0; i < toAddress.size(); i++) { + address[i]=new InternetAddress(toAddress.get(i)); + } + mailMessage.setRecipients(Message.RecipientType.TO,address); + }else{ + toAddress=mailInfo.getToAddress(); + Address to = new InternetAddress(toAddress.get(0)); + // Message.RecipientType.TO属性表示接收者的类型为TO + mailMessage.setRecipient(Message.RecipientType.TO,to); + } + + // 设置邮件消息的主题 + mailMessage.setSubject(mailInfo.getSubject()); + // 设置邮件消息发送的时间 + mailMessage.setSentDate(new Date()); + // MiniMultipart类是一个容器类,包含MimeBodyPart类型的对象 + Multipart mainPart = new MimeMultipart(); + // 创建一个包含HTML内容的MimeBodyPart + BodyPart html = new MimeBodyPart(); + // 设置HTML内容 + html.setContent(mailInfo.getContent(), "text/html; charset=utf-8"); + mainPart.addBodyPart(html); + if(mailInfo.getAttachFileNames()!=null){ + List attachFileNames = mailInfo.getAttachFileNames(); + for (String path : attachFileNames) { + html=new MimeBodyPart(); + FileDataSource fds=new FileDataSource(path); //得到数据源 + html.setDataHandler(new DataHandler(fds)); //得到附件本身并至入BodyPart + //此处是为了解决附件中文名乱码的问题 + String fileName= MimeUtility.encodeText(fds.getName()); + html.setFileName(fileName); //得到文件名同样至入BodyPart + mainPart.addBodyPart(html); + } + } + + // 将MiniMultipart对象设置为邮件内容 + mailMessage.setContent(mainPart); + // 发送邮件 + Transport.send(mailMessage); + return true; + } catch (MessagingException ex) { + ex.printStackTrace(); + } + return false; + } + + +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MyPageHelper.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MyPageHelper.java new file mode 100644 index 0000000..9005bf4 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/MyPageHelper.java @@ -0,0 +1,15 @@ +package com.hcframe.base.common.utils; + +import com.hcframe.base.common.WebPageInfo; +import com.github.pagehelper.PageHelper; + +public class MyPageHelper { + + public static void start(WebPageInfo webPageInfo) { + if (WebPageInfo.hasSort(webPageInfo)) { + PageHelper.startPage(webPageInfo.getPageNum(), webPageInfo.getPageSize(), webPageInfo.getSortSql()); + } else { + PageHelper.startPage(webPageInfo.getPageNum(), webPageInfo.getPageSize()); + } + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/ObjectUtil.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/ObjectUtil.java new file mode 100644 index 0000000..8eab067 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/ObjectUtil.java @@ -0,0 +1,133 @@ +package com.hcframe.base.common.utils; + + +import com.hcframe.base.common.ServiceException; +import com.hcframe.base.module.data.annotation.DataIgnore; +import com.hcframe.base.module.data.exception.BaseMapperException; +import com.hcframe.base.module.data.module.DataMap; + +import javax.persistence.Id; +import javax.persistence.Table; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ObjectUtil { + + private static final String SERIAL_VERSION_UID = "serialVersionUID"; + private static final String STRING = "class java.lang.String"; + private static final String INTEGER = "class java.lang.Integer"; + private static final String LONG = "class java.lang.LONG"; + + public static Map objToMap(Object obj) { + Map map = new HashMap(); + Class clazz = obj.getClass(); + for (Field field : clazz.getDeclaredFields()) { + field.setAccessible(true); + String fieldName = field.getName(); + try { + if (!org.springframework.util.StringUtils.isEmpty(field.get(obj)) && !fieldName.equals(SERIAL_VERSION_UID)) { + Object value = field.get(obj); + map.put(fieldName, value); + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + return map; + } + + public static void objToSqlMap(Object obj, DataMap dataMap) { + Class clazz = obj.getClass(); + Map map = new HashMap(clazz.getDeclaredFields().length); + List fieldList = new ArrayList<>(); + if (clazz.getAnnotation(Table.class) != null) { + Table table = clazz.getAnnotation(Table.class); + dataMap = dataMap.toBuilder().tableName(table.name()).build(); + } + for (Field field : clazz.getDeclaredFields()) { + field.setAccessible(true); + String fieldName = field.getName(); + if (field.getAnnotation(Id.class) != null) { + dataMap = dataMap.toBuilder().pkName(StringUtils.toUnderScoreUpperCase(fieldName)).build(); + } + try { + if (!fieldName.equals(SERIAL_VERSION_UID)) { + if (!org.springframework.util.StringUtils.isEmpty(field.get(obj))) { + Object value = field.get(obj); + map.put(StringUtils.toUnderScoreUpperCase(fieldName), value); + } + if (field.getAnnotation(DataIgnore.class) == null) { + fieldList.add(StringUtils.toUnderScoreUpperCase(fieldName)); + } + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + dataMap.toBuilder().data(map).fieldList(fieldList).build(); + } + + public static void objToSqlMap(Object obj, DataMap.DataMapBuilder dataMap) { + Class clazz = obj.getClass(); + Map map = new HashMap(clazz.getDeclaredFields().length); + List fieldList = new ArrayList<>(); + if (clazz.getAnnotation(Table.class) != null) { + Table table = clazz.getAnnotation(Table.class); + if (StringUtils.isEmpty(table.name())) { + throw new BaseMapperException("请检查实体类是否添加注解@Table,并且name中是否正确设置了表名"); + } + dataMap = dataMap.tableName(table.name()); + } + for (Field field : clazz.getDeclaredFields()) { + field.setAccessible(true); + String fieldName = field.getName(); + if (field.getAnnotation(Id.class) != null) { + dataMap = dataMap.pkName(StringUtils.toUnderScoreUpperCase(fieldName)); + } + try { + if (!fieldName.equals(SERIAL_VERSION_UID)) { + if (!org.springframework.util.StringUtils.isEmpty(field.get(obj))) { + Object value = field.get(obj); + map.put(StringUtils.toUnderScoreUpperCase(fieldName), value); + } + if (field.getAnnotation(DataIgnore.class) == null) { + fieldList.add(StringUtils.toUnderScoreUpperCase(fieldName)); + } + } + + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + dataMap.data(map).fieldList(fieldList); + } + + public static void setField(Object obj, String key, Object value) { + Class clazz = obj.getClass(); + try { + Field field = clazz.getDeclaredField(key); + field.setAccessible(true); + String str = field.getGenericType().toString(); + if (STRING.equals(str)) { + value = value.toString(); + } + if (INTEGER.equals(str)) { + value = Integer.valueOf(value.toString()); + } + if (LONG.equals(str)) { + value = Long.valueOf(value.toString()); + } + try { + field.set(obj, value); + } catch (IllegalAccessException e) { + throw new ServiceException("字段类型不匹配", e); + } + } catch (NoSuchFieldException e) { + throw new ServiceException("无法找到相应的字段", e); + } + } + +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/RandomUtil.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/RandomUtil.java new file mode 100644 index 0000000..2637785 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/RandomUtil.java @@ -0,0 +1,18 @@ +package com.hcframe.base.common.utils; + +import java.util.Random; + +public class RandomUtil { + + + public static String getrandom() { + StringBuilder code = new StringBuilder(); + Random random = new Random(); + for (int i = 0; i < 6; i++) { + int r = random.nextInt(10); + code.append(r); + } + return code.toString(); + + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/RedisUtil.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/RedisUtil.java new file mode 100644 index 0000000..b2129bd --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/RedisUtil.java @@ -0,0 +1,584 @@ +package com.hcframe.base.common.utils; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import com.hcframe.base.common.config.FrameConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; + + +/** + * Redis工具类 + */ + +@Component +public final class RedisUtil { + + // url + public static boolean isUseful; + + // 通过yml文件获取host + @Autowired + public void setHost(FrameConfig config) { + RedisUtil.isUseful = config.getIsRedisLogin(); + } + + private final static Logger logger = LoggerFactory.getLogger(RedisUtil.class); + + @Resource + private RedisTemplate redisTemplate; + + /** + * 指定缓存失效时间 + * + * @param key 键 + * @param time 时间(秒) + * @return + */ + public boolean expire(String key, long time) { + try { + if (time > 0) { + redisTemplate.expire(key, time, TimeUnit.SECONDS); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 根据key 获取过期时间 + * + * @param key 键 不能为null + * @return 时间(秒) 返回0代表为永久有效 + */ + public long getExpire(String key) { + return redisTemplate.getExpire(key, TimeUnit.SECONDS); + } + + /** + * 判断key是否存在 + * + * @param key 键 + * @return true 存在 false不存在 + */ + public boolean hasKey(String key) { + try { + return redisTemplate.hasKey(key); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 删除缓存 + * + * @param key 可以传一个值 或多个 + */ + @SuppressWarnings("unchecked") + public void del(String... key) { + if (key != null && key.length > 0) { + if (key.length == 1) { + redisTemplate.delete(key[0]); + } else { + redisTemplate.delete(CollectionUtils.arrayToList(key)); + } + } + } + // ============================String============================= + + /** + * 普通缓存获取 + * + * @param key 键 + * @return 值 + */ + public Object get(String key) { + return key == null ? null : redisTemplate.opsForValue().get(key); + } + + /** + * 普通缓存放入 + * + * @param key 键 + * @param value 值 + * @return true成功 false失败 + */ + public boolean set(String key, Object value) { + try { + redisTemplate.opsForValue().set(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 普通缓存放入并设置时间 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 + * @return true成功 false 失败 + */ + public boolean set(String key, Object value, long time) { + try { + if (time > 0) { + redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); + } else { + set(key, value); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 递增 + * + * @param key 键 + * @param delta 要增加几(大于0) + * @return + */ + public long incr(String key, long delta) { + if (delta < 0) { + throw new RuntimeException("递增因子必须大于0"); + } + return redisTemplate.opsForValue().increment(key, delta); + } + + /** + * 递减 + * + * @param key 键 + * @param delta 要减少几(小于0) + * @return + */ + public long decr(String key, long delta) { + if (delta < 0) { + throw new RuntimeException("递减因子必须大于0"); + } + return redisTemplate.opsForValue().increment(key, -delta); + } + // ================================Map================================= + + /** + * HashGet + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return 值 + */ + public Object hget(String key, String item) { + return redisTemplate.opsForHash().get(key, item); + } + + /** + * 获取hashKey对应的所有键值 + * + * @param key 键 + * @return 对应的多个键值 + */ + public Map hmget(String key) { + return redisTemplate.opsForHash().entries(key); + } + + /** + * HashSet + * + * @param key 键 + * @param map 对应多个键值 + * @return true 成功 false 失败 + */ + public boolean hmset(String key, Map map) { + try { + redisTemplate.opsForHash().putAll(key, map); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * HashSet 并设置时间 + * + * @param key 键 + * @param map 对应多个键值 + * @param time 时间(秒) + * @return true成功 false失败 + */ + public boolean hmset(String key, Map map, long time) { + try { + redisTemplate.opsForHash().putAll(key, map); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value) { + try { + redisTemplate.opsForHash().put(key, item, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value, long time) { + try { + redisTemplate.opsForHash().put(key, item, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 删除hash表中的值 + * + * @param key 键 不能为null + * @param item 项 可以使多个 不能为null + */ + public void hdel(String key, Object... item) { + redisTemplate.opsForHash().delete(key, item); + } + + /** + * 判断hash表中是否有该项的值 + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return true 存在 false不存在 + */ + public boolean hHasKey(String key, String item) { + return redisTemplate.opsForHash().hasKey(key, item); + } + + /** + * hash递增 如果不存在,就会创建一个 并把新增后的值返回 + * + * @param key 键 + * @param item 项 + * @param by 要增加几(大于0) + * @return + */ + public double hincr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, by); + } + + /** + * hash递减 + * + * @param key 键 + * @param item 项 + * @param by 要减少记(小于0) + * @return + */ + public double hdecr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, -by); + } + // ============================set============================= + + /** + * 根据key获取Set中的所有值 + * + * @param key 键 + * @return + */ + public Set sGet(String key) { + try { + return redisTemplate.opsForSet().members(key); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 根据value从一个set中查询,是否存在 + * + * @param key 键 + * @param value 值 + * @return true 存在 false不存在 + */ + public boolean sHasKey(String key, Object value) { + try { + return redisTemplate.opsForSet().isMember(key, value); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将数据放入set缓存 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSet(String key, Object... values) { + try { + return redisTemplate.opsForSet().add(key, values); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 将set数据放入缓存 + * + * @param key 键 + * @param time 时间(秒) + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSetAndTime(String key, long time, Object... values) { + try { + Long count = redisTemplate.opsForSet().add(key, values); + if (time > 0) { + expire(key, time); + } + return count; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 获取set缓存的长度 + * + * @param key 键 + * @return + */ + public long sGetSetSize(String key) { + try { + return redisTemplate.opsForSet().size(key); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 移除值为value的 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 移除的个数 + */ + public long setRemove(String key, Object... values) { + try { + Long count = redisTemplate.opsForSet().remove(key, values); + return count; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + // ===============================list================================= + + /** + * 获取list缓存的内容 + * + * @param key 键 + * @param start 开始 + * @param end 结束 0 到 -1代表所有值 + * @return + */ + public List lGet(String key, long start, long end) { + try { + return redisTemplate.opsForList().range(key, start, end); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 获取list缓存的长度 + * + * @param key 键 + * @return + */ + public long lGetListSize(String key) { + try { + return redisTemplate.opsForList().size(key); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + /** + * 通过索引 获取list中的值 + * + * @param key 键 + * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 + * @return + */ + public Object lGetIndex(String key, long index) { + try { + return redisTemplate.opsForList().index(key, index); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @return + */ + public boolean lSet(String key, Object value) { + try { + redisTemplate.opsForList().rightPush(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, Object value, long time) { + try { + redisTemplate.opsForList().rightPush(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @return + */ + public boolean lSet(String key, List value) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, List value, long time) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 根据索引修改list中的某条数据 + * + * @param key 键 + * @param index 索引 + * @param value 值 + * @return + */ + public boolean lUpdateIndex(String key, long index, Object value) { + try { + redisTemplate.opsForList().set(key, index, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 移除N个值为value + * + * @param key 键 + * @param count 移除多少个 + * @param value 值 + * @return 移除的个数 + */ + public long lRemove(String key, long count, Object value) { + try { + return redisTemplate.opsForList().remove(key, count, value); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/RegexUtil.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/RegexUtil.java new file mode 100644 index 0000000..bf35e6f --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/RegexUtil.java @@ -0,0 +1,11 @@ +package com.hcframe.base.common.utils; + +import java.util.regex.Pattern; + +public class RegexUtil { + + public static boolean isChinese(String str) { + String pattern = "^([\\u4E00-\\u9FA5])*$"; + return Pattern.matches(pattern, str); + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/SpringContextUtil.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/SpringContextUtil.java new file mode 100644 index 0000000..892bad1 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/SpringContextUtil.java @@ -0,0 +1,30 @@ +package com.hcframe.base.common.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 applicationContext; + //获取上下文 + public static ApplicationContext getApplicationContext() { + return applicationContext; + } + + //设置上下文 + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + SpringContextUtil.applicationContext = applicationContext; + } + + //通过名字获取上下文中的bean + public static Object getBean(String name){ + return applicationContext.getBean(name); + } + //通过类型获取上下文中的bean + public static Object getBean(Class requiredType){ + return applicationContext.getBean(requiredType); + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/StringUtils.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/StringUtils.java new file mode 100644 index 0000000..f50521d --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/StringUtils.java @@ -0,0 +1,417 @@ +package com.hcframe.base.common.utils; + +import java.util.*; + + +/** + * 字符串工具类 + * + * @author ruoyi + */ +public class StringUtils extends org.apache.commons.lang3.StringUtils { + /** + * 空字符串 + */ + private static final String NULLSTR = ""; + + /** + * 下划线 + */ + private static final char SEPARATOR = '_'; + + /** + * 获取参数不为空值 + * + * @param value defaultValue 要判断的value + * @return value 返回值 + */ + public static T nvl(T value, T defaultValue) { + return value != null ? value : defaultValue; + } + + /** + * * 判断一个Collection是否为空, 包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Collection coll) { + return isNull(coll) || coll.isEmpty(); + } + + /** + * * 判断一个Collection是否非空,包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Collection coll) { + return !isEmpty(coll); + } + + /** + * * 判断一个对象数组是否为空 + * + * @param objects 要判断的对象数组 + * * @return true:为空 false:非空 + */ + public static boolean isEmpty(Object[] objects) { + return isNull(objects) || (objects.length == 0); + } + + /** + * * 判断一个对象数组是否非空 + * + * @param objects 要判断的对象数组 + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Object[] objects) { + return !isEmpty(objects); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Map map) { + return isNull(map) || map.isEmpty(); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Map map) { + return !isEmpty(map); + } + + /** + * * 判断一个字符串是否为空串 + * + * @param str String + * @return true:为空 false:非空 + */ + public static boolean isEmpty(String str) { + return isNull(str) || NULLSTR.equals(str.trim()); + } + + /** + * * 判断一个字符串是否为非空串 + * + * @param str String + * @return true:非空串 false:空串 + */ + public static boolean isNotEmpty(String str) { + return !isEmpty(str); + } + + /** + * * 判断一个对象是否为空 + * + * @param object Object + * @return true:为空 false:非空 + */ + public static boolean isNull(Object object) { + return object == null; + } + + /** + * * 判断一个对象是否非空 + * + * @param object Object + * @return true:非空 false:空 + */ + public static boolean isNotNull(Object object) { + return !isNull(object); + } + + /** + * * 判断一个对象是否是数组类型(Java基本型别的数组) + * + * @param object 对象 + * @return true:是数组 false:不是数组 + */ + public static boolean isArray(Object object) { + return isNotNull(object) && object.getClass().isArray(); + } + + /** + * 去空格 + */ + public static String trim(String str) { + return (str == null ? "" : str.trim()); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @return 结果 + */ + public static String substring(final String str, int start) { + if (str == null) { + return NULLSTR; + } + + if (start < 0) { + start = str.length() + start; + } + + if (start < 0) { + start = 0; + } + if (start > str.length()) { + return NULLSTR; + } + + return str.substring(start); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @param end 结束 + * @return 结果 + */ + public static String substring(final String str, int start, int end) { + if (str == null) { + return NULLSTR; + } + + if (end < 0) { + end = str.length() + end; + } + if (start < 0) { + start = str.length() + start; + } + + if (end > str.length()) { + end = str.length(); + } + + if (start > end) { + return NULLSTR; + } + + if (start < 0) { + start = 0; + } + if (end < 0) { + end = 0; + } + + return str.substring(start, end); + } + + /** + * 字符串转set + * + * @param str 字符串 + * @param sep 分隔符 + * @return set集合 + */ + public static final Set str2Set(String str, String sep) { + return new HashSet(str2List(str, sep, true, false)); + } + + /** + * 字符串转list + * + * @param str 字符串 + * @param sep 分隔符 + * @param filterBlank 过滤纯空白 + * @param trim 去掉首尾空白 + * @return list集合 + */ + public static final List str2List(String str, String sep, boolean filterBlank, boolean trim) { + List list = new ArrayList(); + if (StringUtils.isEmpty(str)) { + return list; + } + + // 过滤空白字符串 + if (filterBlank && StringUtils.isBlank(str)) { + return list; + } + String[] split = str.split(sep); + for (String string : split) { + if (filterBlank && StringUtils.isBlank(string)) { + continue; + } + if (trim) { + string = string.trim(); + } + list.add(string); + } + + return list; + } + + /** + * 下划线转驼峰命名 + */ + public static String toUnderScoreCase(String str) { + if (str == null) { + return null; + } + StringBuilder sb = new StringBuilder(); + // 前置字符是否大写 + boolean preCharIsUpperCase = true; + // 当前字符是否大写 + boolean curreCharIsUpperCase = true; + // 下一字符是否大写 + boolean nexteCharIsUpperCase = true; + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (i > 0) { + preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); + } else { + preCharIsUpperCase = false; + } + + curreCharIsUpperCase = Character.isUpperCase(c); + + if (i < (str.length() - 1)) { + nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); + } + + if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) { + sb.append(SEPARATOR); + } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) { + sb.append(SEPARATOR); + } + sb.append(Character.toLowerCase(c)); + } + + return sb.toString(); + } + + /** + * 下划线转驼峰命名 + */ + public static String toUnderScoreUpperCase(String str) { + if (str == null) { + return null; + } + StringBuilder sb = new StringBuilder(); + // 前置字符是否大写 + boolean preCharIsUpperCase = true; + // 当前字符是否大写 + boolean curreCharIsUpperCase = true; + // 下一字符是否大写 + boolean nexteCharIsUpperCase = true; + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (i > 0) { + preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); + } else { + preCharIsUpperCase = false; + } + + curreCharIsUpperCase = Character.isUpperCase(c); + + if (i < (str.length() - 1)) { + nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); + } + + if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) { + sb.append(SEPARATOR); + } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) { + sb.append(SEPARATOR); + } + sb.append(Character.toLowerCase(c)); + } + + return sb.toString().toUpperCase(); + } + + /** + * 是否包含字符串 + * + * @param str 验证字符串 + * @param strs 字符串组 + * @return 包含返回true + */ + public static boolean inStringIgnoreCase(String str, String... strs) { + if (str != null && strs != null) { + for (String s : strs) { + if (str.equalsIgnoreCase(trim(s))) { + return true; + } + } + } + return false; + } + + /** + * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld + * + * @param name 转换前的下划线大写方式命名的字符串 + * @return 转换后的驼峰式命名的字符串 + */ + public static String convertToCamelCase(String name) { + StringBuilder result = new StringBuilder(); + // 快速检查 + if (name == null || name.isEmpty()) { + // 没必要转换 + return ""; + } else if (!name.contains("_")) { + // 不含下划线,仅将首字母大写 + return name.substring(0, 1).toUpperCase() + name.substring(1); + } + // 用下划线将原始字符串分割 + String[] camels = name.split("_"); + for (String camel : camels) { + // 跳过原始字符串中开头、结尾的下换线或双重下划线 + if (camel.isEmpty()) { + continue; + } + // 首字母大写 + result.append(camel.substring(0, 1).toUpperCase()); + result.append(camel.substring(1).toLowerCase()); + } + return result.toString(); + } + + /** + * 驼峰式命名法 例如:user_name->userName + */ + public static String toCamelCase(String s) { + if (s == null) { + return null; + } + s = s.toLowerCase(); + StringBuilder sb = new StringBuilder(s.length()); + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + + if (c == SEPARATOR) { + upperCase = true; + } else if (upperCase) { + sb.append(Character.toUpperCase(c)); + upperCase = false; + } else { + sb.append(c); + } + } + return sb.toString(); + } + + @SuppressWarnings("unchecked") + public static T cast(Object obj) { + return (T) obj; + } + + public static void main(String[] args) { + Long l = 1l; + System.out.println(l.toString()); + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/TableNameUtil.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/TableNameUtil.java new file mode 100644 index 0000000..7bc3abb --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/TableNameUtil.java @@ -0,0 +1,51 @@ +package com.hcframe.base.common.utils; + +import com.hcframe.base.module.cache.emum.CacheType; +import com.hcframe.base.module.cache.impl.TableCache; +import com.hcframe.base.module.tableconfig.dao.OsSysTableMapper; +import com.hcframe.base.module.tableconfig.entity.OsSysTable; +import lombok.val; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +public class TableNameUtil { + + final + OsSysTableMapper osSysTableMapper; + + private final TableCache tableCache; + + public TableNameUtil(OsSysTableMapper osSysTableMapper, TableCache tableCache) { + this.osSysTableMapper = osSysTableMapper; + this.tableCache = tableCache; + } + + public OsSysTable getTableName(String typeName) { + // 缓存中读取 + OsSysTable osSysTable = tableCache.getCacheValue(CacheType.tableCache, typeName, OsSysTable.class); + JudgeException.isNull(osSysTable, "输入URL错误"); + return osSysTable; + } + + public OsSysTable getTableAllInfo(String typeName) { + // 缓存中读取 + OsSysTable osSysTable = tableCache.getCacheValue(CacheType.tableCache, typeName, OsSysTable.class); + JudgeException.isNull(osSysTable, "输入URL错误"); + return osSysTable; + } + + public Map getBaseTableInfo(String tableNames) { + String[] tableNameArr = tableNames.split(","); + Map resultMap = new HashMap<>(tableNameArr.length); + for (String tableName : tableNameArr) { + // 读取缓存 + val list = tableCache.getCacheValue(CacheType.baseCache, tableName, List.class); + resultMap.put(tableName, list); + } + return resultMap; + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/TokenProccessor.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/TokenProccessor.java new file mode 100644 index 0000000..58905c4 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/TokenProccessor.java @@ -0,0 +1,34 @@ +package com.hcframe.base.common.utils; + +import java.util.Random; + +/** + * 生成Token的工具类 + * + */ +public class TokenProccessor { + + private TokenProccessor(){} + + private static final TokenProccessor instance = new TokenProccessor(); + + public static TokenProccessor getInstance() { + return instance; + } + + /** + * 生成Token + * @return + */ + public String makeToken() { + String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + ""; + EncryptUtil encryptUtil = EncryptUtil.getInstance(); + String str = encryptUtil.MD5(token); + str = str.replaceAll("/", ""); + str = str.replaceAll("\\+", ""); + str = str.replaceAll("=", ""); + return str; + } + + +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/UserInfoUtil.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/UserInfoUtil.java new file mode 100644 index 0000000..348ece6 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/UserInfoUtil.java @@ -0,0 +1,60 @@ +package com.hcframe.base.common.utils; + +import com.hcframe.base.module.shiro.FtToken; +import com.hcframe.base.module.shiro.service.ShiroService; +import org.apache.shiro.SecurityUtils; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.Date; + +@Component +public class UserInfoUtil { + + @Resource + ShiroService shiroService; + + /** + * 通过request返回用户信息 + * @param request request + * @return 用户类型 + */ + public T getUserInfoByRequest(HttpServletRequest request) { + String token = request.getHeader("X-Access-Token"); + if (StringUtils.isEmpty(token)) { + return null; + } + FtToken ftToken = shiroService.findByToken(token); + Date expireData= ftToken.getExpireTime(); + Date date = new Date(); + if (date.getTime() > expireData.getTime()) { + return null; + } + return (T) shiroService.findByUserId(ftToken.getUserId()); + } + + /** + * 获取当前用户信息 + * @param 用户实体类泛型 + * @return 返回结果 + */ + public static T getUserInfo(){ + return (T)SecurityUtils.getSubject().getPrincipal(); + } + + /** + * 获取当前用户token + * @param request + * @return + */ + public static String getUserToken(HttpServletRequest request){ + String token = request.getHeader("X-Access-Token"); + //如果header中不存在token,则从参数中获取token + if (org.apache.commons.lang3.StringUtils.isBlank(token)) { + token = request.getParameter("token"); + } + return token; + } +} diff --git a/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/XssClass.java b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/XssClass.java new file mode 100644 index 0000000..1f908b6 --- /dev/null +++ b/hcframe-parent/hcframe-base/src/main/java/com/hcframe/base/common/utils/XssClass.java @@ -0,0 +1,18 @@ +package com.hcframe.base.common.utils; + +import static org.thymeleaf.util.StringUtils.split; + +public class XssClass { + + public static boolean sqlInj(String str){ + String injStr = "'|and|exec|insert|select|delete|update|"+ + "count|*|%|chr|mid|master|truncate|char|declare|;|or|+|,| \ No newline at end of file diff --git a/hcframe-parent/hcframe-user/pom.xml b/hcframe-parent/hcframe-user/pom.xml new file mode 100644 index 0000000..1479bd3 --- /dev/null +++ b/hcframe-parent/hcframe-user/pom.xml @@ -0,0 +1,48 @@ + + + + parent + com.hcframe + 1.0-SNAPSHOT + + 4.0.0 + + hcframe-user + + + 8 + 8 + + + + com.hcframe + hcframe-base + 1.2.1-SNAPSHOT + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-test + + + org.junit.vintage + junit-vintage-engine + + + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/UserApplication.java b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/UserApplication.java new file mode 100644 index 0000000..bdfad10 --- /dev/null +++ b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/UserApplication.java @@ -0,0 +1,24 @@ +package com.hcframe.user; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.web.servlet.ServletComponentScan; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) +@EnableAspectJAutoProxy(proxyTargetClass = true) +@EnableSwagger2 +@ServletComponentScan +@EnableCaching +//@EnableDiscoveryClient +//@EnableFeignClients +@ComponentScan(basePackages = {"com.hcframe.**"}) +public class UserApplication { + public static void main(String[] args) { + SpringApplication.run(UserApplication.class, args); + } +} diff --git a/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/common/config/CommandLineRunnerImpl.java b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/common/config/CommandLineRunnerImpl.java new file mode 100644 index 0000000..21dca27 --- /dev/null +++ b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/common/config/CommandLineRunnerImpl.java @@ -0,0 +1,36 @@ +package com.hcframe.user.common.config; + +import com.hcframe.base.module.cache.CacheService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; +import com.hcframe.base.module.datasource.utils.DataSourceUtil; + +import java.util.List; + + +/** + * @author lhc + * @date 2020-10-09 + * @description springboot启动执行配置类 + */ +@Component +public class CommandLineRunnerImpl implements CommandLineRunner { + + private static final Logger logger = LoggerFactory.getLogger(CommandLineRunnerImpl.class); + + @Autowired + List cacheServices; + + @Override + public void run(String... args) { + DataSourceUtil.initDataSource(); + // 初始化缓存 +// for (CacheService cacheService : cacheServices) { +// cacheService.initTableCache(); +// } + logger.info("start success"); + } +} diff --git a/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/common/config/ShiroRealmConfig.java b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/common/config/ShiroRealmConfig.java new file mode 100644 index 0000000..4c79027 --- /dev/null +++ b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/common/config/ShiroRealmConfig.java @@ -0,0 +1,80 @@ +package com.hcframe.user.common.config; + +import com.hcframe.base.module.auth.dao.FtUserDao; +import com.hcframe.base.module.auth.entity.FtUser; +import com.hcframe.base.module.shiro.service.ShiroType; +import com.hcframe.base.module.shiro.service.SystemRealm; +import org.apache.shiro.authz.SimpleAuthorizationInfo; +import org.springframework.stereotype.Component; + +import java.util.LinkedHashMap; + +/** + * @author lhc + * @date 2021-02-05 + * @decription shiro 配置类 + */ +@Component +public class ShiroRealmConfig implements SystemRealm { + + final + FtUserDao ftUserDao; + + public ShiroRealmConfig(FtUserDao ftUserDao) { + this.ftUserDao = ftUserDao; + } + + /** + * 根据用户信息注入权限 + * @param user 用户信息 + * @return 权限信息 + */ + @Override + public SimpleAuthorizationInfo setAuthoriztion(Object user) { + return new SimpleAuthorizationInfo(); + } + + /** + * 根据用户Id查询用户信息并注入到shiro框架中 + * @param userId 用户id + * @return 用户信息 + */ + @Override + public Object findByUserId(String userId) { + return ftUserDao.selectOne(FtUser.builder().userId(Integer.parseInt(userId)).build()); + } + + /** + * 配置拦截及放行路径 + * @return 返回拦截及放行路径Map + */ + @Override + public LinkedHashMap setShiroUrl() { + LinkedHashMap map = new LinkedHashMap<>(); + // 用户登陆 + map.put("/ftUser/login", ShiroType.ANON); + // Vue静态资源 + map.put("/img/**", ShiroType.ANON); + map.put("/static/**", ShiroType.ANON); + map.put("/tinymce/**", ShiroType.ANON); + map.put("/favicon.ico", ShiroType.ANON); + map.put("/manifest.json", ShiroType.ANON); + map.put("/robots.txt", ShiroType.ANON); + map.put("/precache*", ShiroType.ANON); + map.put("/service-worker.js", ShiroType.ANON); + // swagger UI 静态资源 + map.put("/swagger-ui.html",ShiroType.ANON); + map.put("/doc.html",ShiroType.ANON); + map.put("/swagger-resources/**",ShiroType.ANON); + map.put("/webjars/**",ShiroType.ANON); + map.put("/v2/api-docs",ShiroType.ANON); + map.put("/v2/api-docs-ext",ShiroType.ANON); + map.put("/swagger/**",ShiroType.ANON); + // druid 资源路径 + map.put("/druid/**",ShiroType.ANON); + // 其余路径均拦截 + map.put("/**", ShiroType.ANON); + return map; + } + +} diff --git a/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/controller/ManageController.java b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/controller/ManageController.java new file mode 100644 index 0000000..0c69e0b --- /dev/null +++ b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/controller/ManageController.java @@ -0,0 +1,24 @@ +package com.hcframe.user.module.manage.controller; + +import com.hcframe.user.module.manage.service.ManageService; +import io.swagger.annotations.Api; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author lhc + * @date 2021-02-05 + */ +@Api(tags = "用户管理") +@RequestMapping("manage") +@RestController +public class ManageController { + + final + ManageService manageService; + + public ManageController(ManageService manageService) { + this.manageService = manageService; + } + +} diff --git a/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/controller/ManageDataController.java b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/controller/ManageDataController.java new file mode 100644 index 0000000..4fc3f93 --- /dev/null +++ b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/controller/ManageDataController.java @@ -0,0 +1,15 @@ +package com.hcframe.user.module.manage.controller; + +import io.swagger.annotations.Api; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author lhc + */ +@Api(tags = "用户管理对外数据接口") +@RequestMapping("manage/data") +@RestController +public class ManageDataController { + +} diff --git a/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/service/ManageDataService.java b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/service/ManageDataService.java new file mode 100644 index 0000000..66e5b2c --- /dev/null +++ b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/service/ManageDataService.java @@ -0,0 +1,4 @@ +package com.hcframe.user.module.manage.service; + +public interface ManageDataService { +} diff --git a/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/service/ManageService.java b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/service/ManageService.java new file mode 100644 index 0000000..25cb86b --- /dev/null +++ b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/service/ManageService.java @@ -0,0 +1,4 @@ +package com.hcframe.user.module.manage.service; + +public interface ManageService { +} diff --git a/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/service/impl/ManageServiceDataImpl.java b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/service/impl/ManageServiceDataImpl.java new file mode 100644 index 0000000..c75a5b1 --- /dev/null +++ b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/service/impl/ManageServiceDataImpl.java @@ -0,0 +1,23 @@ +package com.hcframe.user.module.manage.service.impl; + +import com.hcframe.base.module.data.module.BaseMapper; +import com.hcframe.base.module.data.module.BaseMapperImpl; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import com.hcframe.user.module.manage.service.ManageService; + +/** + * @author lhc + * @date 2021-02-05 + */ +@Service +public class ManageServiceDataImpl implements ManageService { + + final BaseMapper baseMapper; + + + public ManageServiceDataImpl(@Qualifier(BaseMapperImpl.BASE) BaseMapper baseMapper) { + this.baseMapper = baseMapper; + } + +} diff --git a/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/service/impl/ManageServiceImpl.java b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/service/impl/ManageServiceImpl.java new file mode 100644 index 0000000..9b45a66 --- /dev/null +++ b/hcframe-parent/hcframe-user/src/main/java/com/hcframe/user/module/manage/service/impl/ManageServiceImpl.java @@ -0,0 +1,23 @@ +package com.hcframe.user.module.manage.service.impl; + +import com.hcframe.base.module.data.module.BaseMapper; +import com.hcframe.base.module.data.module.BaseMapperImpl; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import com.hcframe.user.module.manage.service.ManageDataService; + + +/** + * @author lhc + * @date 2021-02-05 + */ +@Service +public class ManageServiceImpl implements ManageDataService { + + + final BaseMapper baseMapper; + + public ManageServiceImpl(@Qualifier(BaseMapperImpl.BASE) BaseMapper baseMapper) { + this.baseMapper = baseMapper; + } +} diff --git a/hcframe-parent/hcframe-user/src/main/resources/application.yml b/hcframe-parent/hcframe-user/src/main/resources/application.yml new file mode 100644 index 0000000..952fba8 --- /dev/null +++ b/hcframe-parent/hcframe-user/src/main/resources/application.yml @@ -0,0 +1,131 @@ +server: + port: 8080 + servlet: + context-path: /user +pagehelper: + auto-runtime-dialect: true +spring: + application: + name: cloud-user + # 缓存设置 + cache: + # redis缓存 +# type: redis +# redis: +# time-to-live: 1d +# use-key-prefix: true +# cache-null-values: true +# key-prefix: cache. + # ehcache缓存 + type: ehcache + ehcache: + config: classpath:ehcache.xml + redis: + database: 0 + host: 192.168.4.119 + port: 6379 + password: + lettuce: + pool: + # 连接池中的最大空闲连接 默认8 + max-idle: 8 + # 连接池中的最小空闲连接 默认0 + min-idle: 0 + # 连接池最大连接数 默认8 ,负数表示没有限制 + max-active: 8 + # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认-1 + max-wait: -1 + timeout: 30000 + mvc: + view: + prefix: classpath*:/templates/ + suffix: .html + static-path-pattern: classpath*:/static/** + datasource: + druid: + # 配置sqlite文件路径,需要填写绝对路径,推荐将sqlite文件放入到服务器上,而非程序jar包或war包中 + driver-class-name: org.sqlite.JDBC + url: jdbc:sqlite:/Volumes/DATA/ideaProject/user/src/main/resources/datasource.db + username: + password: + #使用Druid数据源 + initialSize: 5 + # 初始化大小,最小,最大 + minIdle: 5 + maxActive: 20 + # 配置获取连接等待超时的时间 + maxWait: 60000 + # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + timeBetweenEvictionRunsMillis: 60000 + # 配置一个连接在池中最小生存的时间,单位是毫秒 + minEvictableIdleTimeMillis: 300000 + validationQuery: select 1 + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 + filters: stat,slf4j + # 通过connectProperties属性来打开mergeSql功能;慢SQL记录 + connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 +mybatis: + mapper-locations: classpath*:mapping/**/*.xml + type-aliases-package: com.hcframe.**.entity + configuration: + # 开启Sql日志记录 + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl +# 框架配置 +frame: +# 是否开启redis 用户登录,若开启此项,需要配置redis节点及相关配置,若不开启,需要注释掉redis相关配置信息 + isRedisLogin: true + # 用户登陆超时设置,单位为小时,此值不能为0 + loginTimeout: 4 + # 是否开启controller日志监控 + showControllerLog: true +# swagger配置 +swagger: + # 配置controller包路径 + path: com.hcframe.module.**.controller + # 是否开启权限 + enableAuth: false + # 用户名 + username: admin + # 密码 + password: admin +# Druid连接配置 +druid: + # Druid用户名 + username: test + # Druid密码 + password: test + # Druid 允许访问的IP,默认全部允许 +# allow: 127.0.0.1 + # Druid 拒绝访问的IP,默认不拒绝全部 +# deny: 10.0.0.2 + +eureka: + client: + service-url: + defaultZone: http://admin:123456@192.168.4.119:8081/eureka/ +feign: + client: + config: + default: + connectTimeout: 300000 + readTimeout: 30000 + loggerLevel: basic + okhttp: + enabled: true + hystrix: + enabled: true +# 设置熔断器超时时间 +hystrix: + command: + default: + execution: + isolation: + thread: + timeoutInMilliseconds: 30000 + + + + diff --git a/hcframe-parent/hcframe-user/src/main/resources/banner.txt b/hcframe-parent/hcframe-user/src/main/resources/banner.txt new file mode 100644 index 0000000..0b703cf --- /dev/null +++ b/hcframe-parent/hcframe-user/src/main/resources/banner.txt @@ -0,0 +1,25 @@ + __ __ ______ ______ +| \ | \ / \ / \ +| $$ | $$| $$$$$$\ | $$$$$$\ ______ ______ ______ ____ ______ +| $$__| $$| $$ \$$ | $$_ \$$/ \ | \ | \ \ / \ +| $$ $$| $$ | $$ \ | $$$$$$\ \$$$$$$\| $$$$$$\$$$$\| $$$$$$\ +| $$$$$$$$| $$ __ | $$$$ | $$ \$$/ $$| $$ | $$ | $$| $$ $$ +| $$ | $$| $$__/ \ | $$ | $$ | $$$$$$$| $$ | $$ | $$| $$$$$$$$ __ +| $$ | $$ \$$ $$ | $$ | $$ \$$ $$| $$ | $$ | $$ \$$ \| \ + \$$ \$$ \$$$$$$ \$$ \$$ \$$$$$$$ \$$ \$$ \$$ \$$$$$$$ \$$ + + + + + __ __ _______ __ __ +| \ | \ | \ | \ | \ +| $$\ | $$ ______ | $$$$$$$\ __ __ ______ | $$ | $$ ______ ______ ______ +| $$$\| $$ / \ | $$__/ $$| \ | \ / \ | $$__| $$ / \ / \ / \ +| $$$$\ $$| $$$$$$\ | $$ $$| $$ | $$| $$$$$$\ | $$ $$| $$$$$$\| $$$$$$\| $$$$$$\ +| $$\$$ $$| $$ | $$ | $$$$$$$\| $$ | $$| $$ | $$ | $$$$$$$$| $$ | $$| $$ | $$| $$ $$ +| $$ \$$$$| $$__/ $$ | $$__/ $$| $$__/ $$| $$__| $$ | $$ | $$| $$__/ $$| $$__/ $$| $$$$$$$$ __ +| $$ \$$$ \$$ $$ | $$ $$ \$$ $$ \$$ $$ | $$ | $$ \$$ $$| $$ $$ \$$ \| \ + \$$ \$$ \$$$$$$ \$$$$$$$ \$$$$$$ _\$$$$$$$ \$$ \$$ \$$$$$$ | $$$$$$$ \$$$$$$$ \$$ + | \__| $$ | $$ + \$$ $$ | $$ + \$$$$$$ \$$ \ No newline at end of file diff --git a/hcframe-parent/hcframe-user/src/main/resources/datasource.db b/hcframe-parent/hcframe-user/src/main/resources/datasource.db new file mode 100644 index 0000000000000000000000000000000000000000..feb74e269b64898709e21ab5e549dbf10e920f99 GIT binary patch literal 77824 zcmeI)&rah;9Ki8$LX(o+B($i4t%PKS3kV3yZly{^m6|1KMHj-t23k&$*BPicb_}*d z#jUhepP;Aq)>BV?fFAZS`T~`DXit5E&e#j4(a%igk3Ig(B(jwekGD6R zNSX(J;8~G*UrY$Y5TBT)5XLgvD6Oiqj$T~YpR zteg4O=nlWGZhxan&ZZ~wQ%g(6nH^bAT-mWAEA;z;E!&abmA&EjlWRMTTB~8UY7aIV zW@WgzV$Kyzvl2ILJDrNT-fT5KYwVcKt(Mu`-PkZ6?W}LscJ|GOjeWDW+uB-hsv~YT znytl)h845b__9@)&z^~2-fZi$y;6Q^VZr$JGT!OYfTeo-&ee3P^juCQM}pJsy7Dx! zODuKPiRJdyu{CI%*$JEz8Kg2)1xJmdY#;Y!@Vt3pKKH)(`^~0*UA_Bm@pgV{dD-|O zKRo|!zjxpqre=7OQM_^(lk(>SnQAw}=O7uTw(VMB*zQ?gdIm7sGD*p6B=4YOJmBa&{EYzl+M@Y1o#%_}idjI=x69%D}8QKCSI;w9J)w8aZLR zBM+>;8(q|h^F#Y9=~=@))(7m!&<>oV$nksW4g^xqy~xp5sHdS$#YgHN#j|p-q%beU z_>Zq^=s6Ao2q1s}0tg_0z-R)GGCBPav>)F`JJx}y(IrKI=aPvG=IH&Jp z7gbAjmltnEwb#$~Z>iAF`ehY46?qkJs~A^NP;pDeZ58jTm{7rn00IagfB*srAbGk}WB7gt_2q1s}0tg_000IagfB*srAbc$H*kB?m^l3~2}gTrc)s(xO7uy)?)u8|W{Qyojci6#)bgKmY**5I_I{1Q0*~ftLtO8(HyT Yx3+ihZg+3(i$>2rX|A}ZP5Ht0f9FEKx&QzG literal 0 HcmV?d00001 diff --git a/hcframe-parent/hcframe-user/src/main/resources/ehcache.xml b/hcframe-parent/hcframe-user/src/main/resources/ehcache.xml new file mode 100644 index 0000000..1b8b88f --- /dev/null +++ b/hcframe-parent/hcframe-user/src/main/resources/ehcache.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hcframe-parent/pom.xml b/hcframe-parent/pom.xml new file mode 100644 index 0000000..5f24293 --- /dev/null +++ b/hcframe-parent/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.3.RELEASE + + + com.hcframe + parent + pom + 1.0-SNAPSHOT + + hcframe-base + hcframe-user + storage + + + 8 + 8 + + + + + + + + + + + + + + + + diff --git a/hcframe-parent/storage/pom.xml b/hcframe-parent/storage/pom.xml new file mode 100644 index 0000000..05dddeb --- /dev/null +++ b/hcframe-parent/storage/pom.xml @@ -0,0 +1,203 @@ + + + + parent + com.hcframe + 1.0-SNAPSHOT + + 4.0.0 + + storage + + UTF-8 + UTF-8 + 1.8 + Finchley.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + + org.webjars + webjars-locator + 0.34 + + + org.webjars + vue + 2.5.13 + + + org.webjars.bower + vue-resource + 1.2.1 + + + org.webjars.bower + vue-router + 3.0.1 + + + org.webjars.npm + element-ui + 2.4.3 + + + org.webjars.bower + jquery + 3.3.1 + + + org.webjars.bower + bootstrap + 4.1.3 + + + org.webjars.bower + font-awesome + 4.7.0 + + + org.webjars + ionicons + 2.0.1 + + + org.webjars + fastclick + 1.0.6 + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + mysql + mysql-connector-java + runtime + + + + + + + + + + + + + + + io.springfox + springfox-swagger2 + 2.8.0 + + + io.springfox + springfox-swagger-ui + 2.8.0 + + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + org.springframework.boot + spring-boot-devtools + true + + + + + org.apache.commons + commons-io + 1.3.2 + + + + + org.apache.ant + ant + 1.9.14 + + + org.hibernate + hibernate-validator + 5.1.3.Final + + + + + org.springframework.boot + spring-boot-starter-test + + + org.junit.vintage + junit-vintage-engine + + + test + + + org.apache.commons + commons-lang3 + 3.10 + + + + + + + + + + + + + + + + + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + build-info + + + + + + + diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/StorageApplication.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/StorageApplication.java new file mode 100644 index 0000000..c22babf --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/StorageApplication.java @@ -0,0 +1,16 @@ +package com.sinoparasoft.storage; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.scheduling.annotation.EnableScheduling; + +@SpringBootApplication +@EnableScheduling +@EnableCaching +public class StorageApplication { + + public static void main(String[] args) { + SpringApplication.run(StorageApplication.class, args); + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/api/BucketController.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/api/BucketController.java new file mode 100644 index 0000000..9e0b9c2 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/api/BucketController.java @@ -0,0 +1,58 @@ +package com.sinoparasoft.storage.api; + +import com.sinoparasoft.storage.domain.Bucket; +import com.sinoparasoft.storage.model.BucketQueryRequest; +import com.sinoparasoft.storage.service.BucketService; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.web.bind.annotation.*; + +/** + * 逻辑存储区管理控制类 + * + * @author 袁涛 + * @date 2018.06.08 + */ +@CrossOrigin +@RestController +@RequestMapping("/buckets") +public class BucketController { + /** + * 逻辑存储区管理服务类 + */ + @Autowired + private BucketService bucketService; + + @ApiOperation(value = "获取逻辑存储区列表", notes = "分页查询,获取逻辑存储区列表") + @GetMapping() + public Page findAll(BucketQueryRequest request, Pageable pageable) { + return this.bucketService.findAll(request, pageable); + } + + @ApiOperation(value = "获取逻辑存储区信息", notes = "根据逻辑存储区编号获取逻辑存储区信息") + @GetMapping("/{id:\\d+}") + public Bucket findById(@ApiParam(value = "逻辑存储区编号") @PathVariable Long id) { + return this.bucketService.findById(id); + } + + @ApiOperation(value = "新建逻辑存储区", notes = "新建逻辑存储区") + @PostMapping() + public Bucket create(@RequestBody Bucket request) { + return this.bucketService.create(request); + } + + @ApiOperation(value = "删除逻辑存储区", notes = "删除逻辑存储区") + @DeleteMapping("/{id:\\d+}") + public void delete(@ApiParam(value = "逻辑存储区编号", required = true) @PathVariable Long id) { + this.bucketService.delete(id); + } + + @ApiOperation(value = "更新逻辑存储区", notes = "更新逻辑存储区") + @PutMapping() + public void update(@RequestBody Bucket request) { + this.bucketService.update(request); + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/api/FileController.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/api/FileController.java new file mode 100644 index 0000000..39830ef --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/api/FileController.java @@ -0,0 +1,187 @@ +package com.sinoparasoft.storage.api; + +import com.sinoparasoft.storage.domain.LogicalFile; +import com.sinoparasoft.storage.model.FileBlockCreateRequest; +import com.sinoparasoft.storage.model.FileCreateRequest; +import com.sinoparasoft.storage.model.LogicalFileQueryRequest; +import com.sinoparasoft.storage.service.FileService; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.Resource; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * 文件管理控制类 + * + * @author 袁涛 + * @date 2017.05.10 + */ +@CrossOrigin +@RestController +@RequestMapping("/files") +public class FileController { + /** + * 文件管理服务类 + */ + @Autowired + private FileService fileService; + + @ApiOperation(value = "获取文件列表", notes = "分页查询,获取文件列表") + @GetMapping() + public Page findAll(LogicalFileQueryRequest request, Pageable pageable) { + return this.fileService.findAll(request, pageable); + } + + @ApiOperation(value = "获取文件信息", notes = "根据文件编号获取文件信息") + @GetMapping("/id/{id:\\d+}") + public LogicalFile findById(@ApiParam(value = "文件编号") @PathVariable Long id) { + return this.fileService.findById(id); + } + + @ApiOperation(value = "获取文件信息", notes = "根据文件编号获取文件信息") + @GetMapping("/uuid/{uuid}") + public LogicalFile findByUuid(@ApiParam(value = "文件编号") @PathVariable String uuid) { + return this.fileService.findByUuid(uuid); + } + + @ApiOperation(value = "获取UUID编号", notes = "获取UUID编号") + @GetMapping("/uuid") + public String createUuid() { + return UUID.randomUUID().toString(); + } + + @ApiOperation(value = "新建文件", notes = "新建文件") + @PostMapping() + public LogicalFile create(@RequestParam("bucket_name") String bucketName, + @RequestParam("file") MultipartFile file) { + FileCreateRequest request = new FileCreateRequest(); + request.setBucketName(bucketName); + request.setFile(file); + return this.fileService.create(request); + } + + @ApiOperation(value = "新建文件分块", notes = "新建文件分块") + @PostMapping("/block") + public LogicalFile createBlock(@RequestBody FileBlockCreateRequest request) { + return this.fileService.create(request); + } + + @ApiOperation(value = "新建文件分块", notes = "新建文件分块") + @PostMapping("/block2") + public LogicalFile createBlock2(@RequestParam("bucket_name") String bucketName, + @RequestParam("uuid") String uuid, + @RequestParam("name") String name, + @RequestParam("length") Long length, + @RequestParam("chunk") Integer chunk, + @RequestParam("chunks") Integer chunks, + @RequestParam("file") MultipartFile file) { + FileBlockCreateRequest request = new FileBlockCreateRequest(); + request.setBucketName(bucketName); + request.setUuid(uuid); + request.setName(name); + request.setLength(length); + request.setChunk(chunk); + request.setChunks(chunks); + request.setFile(file); + return this.fileService.create(request); + } + + @ApiOperation(value = "删除文件", notes = "删除文件") + @DeleteMapping("/id/{id:\\d+}") + public void delete(@ApiParam(value = "文件编号", required = true) @PathVariable Long id) { + this.fileService.delete(id); + } + + @ApiOperation(value = "删除文件", notes = "删除文件") + @DeleteMapping("/uuid/{uuid}") + public void delete(@ApiParam(value = "文件编号", required = true) @PathVariable String uuid) { + this.fileService.delete(uuid); + } + + @ApiOperation(value = "更新文件", notes = "更新文件") + @PutMapping() + public void update(@RequestBody LogicalFile request) { + this.fileService.update(request); + } + + @ApiOperation(value = "下载文件", notes = "根据文件编号下载文件") + @GetMapping("/download/id/{id:\\d+}") + public ResponseEntity downloadById(HttpServletRequest request, + @ApiParam(value = "文件编号") @PathVariable Long id) throws IOException { + return this.fileService.download(request, id); + } + + @ApiOperation(value = "下载文件", notes = "根据文件UUID编号下载文件") + @GetMapping("/download/uuid/{uuid}") + public ResponseEntity downloadByUuid(HttpServletRequest request, + @ApiParam(value = "文件编号") @PathVariable String uuid) throws IOException { + return this.fileService.download(request, uuid); + } + + @ApiOperation(value = "批量下载文件", notes = "根据文件UUID编号列表批量下载文件") + @GetMapping("/pldownload") + public ResponseEntity pldownload(HttpServletRequest request, @RequestParam("name") String name, + @RequestParam("uuids") String uuids) throws IOException { + List uuidList = new ArrayList(); + if (uuids != null && !uuids.isEmpty()) { + if (uuids.contains(",")) { + String[] list = uuids.split(","); + for (String uuid : list) { + uuidList.add(uuid); + } + } else { + uuidList.add(uuids); + } + } + return this.fileService.pldownload(request, name, uuidList); + } + + @ApiOperation(value = "浏览文件", notes = "根据文件编号浏览文件") + @GetMapping("/view/id/{id:\\d+}") + public ResponseEntity viewById(HttpServletRequest request, + @ApiParam(value = "文件编号") @PathVariable Long id) throws IOException { + return this.fileService.view(request, id); + } + + @ApiOperation(value = "浏览文件", notes = "根据文件UUID编号浏览文件") + @GetMapping("/view/uuid/{uuid}") + public ResponseEntity viewByUuid(HttpServletRequest request, + @ApiParam(value = "文件编号") @PathVariable String uuid) throws IOException { + return this.fileService.view(request, uuid); + } + + @ApiOperation(value = "开放文件让公开访问", notes = "根据文件编号,开放文件让公开访问") + @PostMapping("/set/id/{id:\\d+}/open") + public void setOpenById(@ApiParam(value = "文件编号", required = true) @PathVariable Long id) { + this.fileService.setOpenById(id); + } + + @ApiOperation(value = "关闭文件不让公开访问", notes = "根据文件编号,关闭文件不让公开访问") + @PostMapping("/set/id/{id:\\d+}/close") + public void setCloseById(@ApiParam(value = "文件编号", required = true) @PathVariable Long id) { + this.fileService.setCloseById(id); + } + + @ApiOperation(value = "开放文件让公开访问", notes = "根据文件UUID编号,开放文件让公开访问") + @GetMapping("/set/uuid/{uuid}/open") + public void setOpenByUuid(@ApiParam(value = "文件编号") @PathVariable String uuid) { + this.fileService.setOpenByUuid(uuid); + } + + @ApiOperation(value = "关闭文件不让公开访问", notes = "根据文件UUID编号,关闭文件不让公开访问") + @GetMapping("/set/uuid/{uuid}/close") + public void setCloseByUuid(@ApiParam(value = "文件编号") @PathVariable String uuid) { + this.fileService.setCloseByUuid(uuid); + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/api/RegionController.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/api/RegionController.java new file mode 100644 index 0000000..b3fb4bd --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/api/RegionController.java @@ -0,0 +1,58 @@ +package com.sinoparasoft.storage.api; + +import com.sinoparasoft.storage.domain.StorageRegion; +import com.sinoparasoft.storage.model.StorageRegionQueryRequest; +import com.sinoparasoft.storage.service.StorageRegionService; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.web.bind.annotation.*; + +/** + * 物理存储区管理控制类 + * + * @author 袁涛 + * @date 2017.12.27 + */ +@CrossOrigin +@RestController +@RequestMapping("/regions") +public class RegionController { + /** + * 存储区管理服务类 + */ + @Autowired + private StorageRegionService storageRegionService; + + @ApiOperation(value = "获取物理存储区列表", notes = "分页查询,获取物理存储区列表") + @GetMapping() + public Page findAll(StorageRegionQueryRequest request, Pageable pageable) { + return this.storageRegionService.findAll(request, pageable); + } + + @ApiOperation(value = "获取物理存储区信息", notes = "根据物理存储区编号获取物理存储区信息") + @GetMapping("/{id:\\d+}") + public StorageRegion findById(@ApiParam(value = "物理存储区编号") @PathVariable Long id) { + return this.storageRegionService.findById(id); + } + + @ApiOperation(value = "新建物理存储区", notes = "新建物理存储区") + @PostMapping() + public StorageRegion create(@RequestBody StorageRegion request) { + return this.storageRegionService.create(request); + } + + @ApiOperation(value = "删除物理存储区", notes = "删除物理存储区") + @DeleteMapping("/{id:\\d+}") + public void delete(@ApiParam(value = "物理存储区编号", required = true) @PathVariable Long id) { + this.storageRegionService.delete(id); + } + + @ApiOperation(value = "更新物理存储区", notes = "更新物理存储区") + @PutMapping() + public void update(@RequestBody StorageRegion request) { + this.storageRegionService.update(request); + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/config/SimpleCORSFilter.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/config/SimpleCORSFilter.java new file mode 100644 index 0000000..09aec41 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/config/SimpleCORSFilter.java @@ -0,0 +1,57 @@ +package com.sinoparasoft.storage.config; + +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.servlet.*; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 跨域支持 + + */ +@WebFilter +@Component +@Order(Ordered.HIGHEST_PRECEDENCE) +public class SimpleCORSFilter implements Filter { + + @Override + public void destroy() { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + /*String[] whiteList = {"http://fwh.castscs.org.cn", "http://localhost"}; + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + String myOrigin = httpServletRequest.getHeader("origin"); + boolean isValid = false; + for( String ip : whiteList ) { + if( myOrigin != null && myOrigin.equals(ip) ){ + isValid = true; + break; + } + }*/ + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + String myOrigin = httpServletRequest.getHeader("origin"); + HttpServletResponse httpServletResponse = (HttpServletResponse) response; + httpServletResponse.setHeader("Access-Control-Allow-Origin", myOrigin); + httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT"); + httpServletResponse.setHeader("Access-Control-Max-Age", "3600"); + httpServletResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with, X-Access-Token, datasource-Key"); + // 是否支持cookie跨域 + httpServletResponse.addHeader("Access-Control-Allow-Credentials", "true"); + chain.doFilter(request, response); + } + + @Override + public void init(FilterConfig arg0) throws ServletException { + + } + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/config/Swagger2Configuration.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/config/Swagger2Configuration.java new file mode 100644 index 0000000..bf93e5d --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/config/Swagger2Configuration.java @@ -0,0 +1,34 @@ +package com.sinoparasoft.storage.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.Contact; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +/** + * Swagger2 配置 + * + * @author 袁涛 + * @date 2018.06.08 + */ +@Configuration +@EnableSwagger2 +public class Swagger2Configuration { + @Bean + public Docket api() { + return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select() + .apis(RequestHandlerSelectors.basePackage("com.sinoparasoft.storage.api")).paths(PathSelectors.any()) + .build(); + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder().title("统一存储API接口文档").description("RESTful风格接口").version("1.0") + .contact(new Contact("袁涛", "url", "yuan-yu-tao@163.com")).build(); + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/config/WebMvcConfig.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/config/WebMvcConfig.java new file mode 100644 index 0000000..7ad9057 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/config/WebMvcConfig.java @@ -0,0 +1,9 @@ +package com.sinoparasoft.storage.config; + +import org.springframework.stereotype.Component; +import org.springframework.web.filter.FormContentFilter; + +@Component +public class WebMvcConfig extends FormContentFilter { + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/Bucket.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/Bucket.java new file mode 100644 index 0000000..7d11a93 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/Bucket.java @@ -0,0 +1,182 @@ +package com.sinoparasoft.storage.domain; + +import io.swagger.annotations.ApiModelProperty; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Date; + +/** + * 逻辑存储区实体类 + * + * @author 袁涛 + * @date 2018.06.07 + */ +@Entity +@Table(name = "bucket") +public class Bucket { + /** + * 编号 + */ + @ApiModelProperty(value = "编号") + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id") + private Long id; + + /** + * 版本 + */ + @ApiModelProperty(value = "版本", hidden = true) + @Version + @Column(name = "version") + private Integer version; + + /** + * 逻辑存储区名称 + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "name") + private String name; + + /** + * 逻辑存储区描述 + */ + @Size(max = 64) + @Column(name = "description") + private String description; + + /** + * 创建时间 + */ + @NotNull + @Column(name = "create_time") + @Temporal(TemporalType.TIMESTAMP) + @DateTimeFormat(style = "M-") + private Date createTime; + + /** + * 修改时间 + */ + @NotNull + @Column(name = "modified_time") + @Temporal(TemporalType.TIMESTAMP) + @DateTimeFormat(style = "M-") + private Date modifiedTime; + + /** + * 元数据,JSON格式 + */ + @Size(max = 1024) + @Column(name = "metadata") + private String metadata; + + /** + * 容量,单位:字节 + */ + @Column(name = "total_size") + private Long totalSize; + + /** + * 已使用容量,单位:字节 + */ + @Column(name = "used_size") + private Long usedSize; + + /** + * 剩余容量,单位:字节 + */ + @Column(name = "available_size") + private Long availableSize; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getModifiedTime() { + return modifiedTime; + } + + public void setModifiedTime(Date modifiedTime) { + this.modifiedTime = modifiedTime; + } + + public String getMetadata() { + return metadata; + } + + public void setMetadata(String metadata) { + this.metadata = metadata; + } + + public Long getTotalSize() { + return totalSize; + } + + public void setTotalSize(Long totalSize) { + this.totalSize = totalSize; + } + + public Long getUsedSize() { + return usedSize; + } + + public void setUsedSize(Long usedSize) { + this.usedSize = usedSize; + } + + public Long getAvailableSize() { + return availableSize; + } + + public void setAvailableSize(Long availableSize) { + this.availableSize = availableSize; + } + + @Override + public String toString() { + return "Bucket [id=" + id + ", version=" + version + ", name=" + name + ", description=" + description + + ", createTime=" + createTime + ", modifiedTime=" + modifiedTime + ", metadata=" + metadata + ", totalSize=" + + totalSize + ", usedSize=" + usedSize + ", availableSize=" + availableSize + "]"; + } + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/HistoryFile.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/HistoryFile.java new file mode 100644 index 0000000..3308db8 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/HistoryFile.java @@ -0,0 +1,186 @@ +package com.sinoparasoft.storage.domain; + +import org.springframework.format.annotation.DateTimeFormat; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Date; + +/** + * 历史文件实体类 + * + * @author 袁涛 + * @date 2017.10.26 + */ +@Entity +@Table(name = "history_file") +public class HistoryFile { + /** + * 编号 + */ + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id") + private Long id; + + /** + * 版本 + */ + @Version + @Column(name = "version") + private Integer version; + + /** + * 文件编号 + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "uuid") + private String uuid; + + /** + * 文件名称 + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "name") + private String name; + + /** + * 物理文件编号 + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "physical_uuid") + private String physicalUuid; + + /** + * 创建时间 + */ + @NotNull + @Column(name = "create_time") + @Temporal(TemporalType.TIMESTAMP) + @DateTimeFormat(style = "M-") + private Date createTime; + + /** + * 修改时间 + */ + @NotNull + @Column(name = "modified_time") + @Temporal(TemporalType.TIMESTAMP) + @DateTimeFormat(style = "M-") + private Date modifiedTime; + + /** + * 元数据,JSON格式 + */ + @NotNull + @Size(max = 1024) + @Column(name = "metadata") + private String metadata; + + /** + * 文件长度,单位:字节 + */ + @NotNull + @Column(name = "length") + private Long length; + + /** + * 文件标签,版本 + */ + @NotNull + @Size(max = 32) + @Column(name = "tag") + private String tag; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPhysicalUuid() { + return physicalUuid; + } + + public void setPhysicalUuid(String physicalUuid) { + this.physicalUuid = physicalUuid; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getModifiedTime() { + return modifiedTime; + } + + public void setModifiedTime(Date modifiedTime) { + this.modifiedTime = modifiedTime; + } + + public String getMetadata() { + return metadata; + } + + public void setMetadata(String metadata) { + this.metadata = metadata; + } + + public Long getLength() { + return length; + } + + public void setLength(Long length) { + this.length = length; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + @Override + public String toString() { + return "HistoryFile [id=" + id + ", version=" + version + ", uuid=" + uuid + ", name=" + name + + ", physicalUuid=" + physicalUuid + ", createTime=" + createTime + ", modifiedTime=" + modifiedTime + + ", metadata=" + metadata + ", length=" + length + ", tag=" + tag + "]"; + } + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/LogicalFile.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/LogicalFile.java new file mode 100644 index 0000000..91ca5ab --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/LogicalFile.java @@ -0,0 +1,230 @@ +package com.sinoparasoft.storage.domain; + +import org.springframework.format.annotation.DateTimeFormat; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Date; + +/** + * 逻辑文件实体类 + * + * @author 袁涛 + * @date 2017.10.26 + */ +@Entity +@Table(name = "logical_file") +public class LogicalFile { + /** + * 编号 + */ + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id") + private Long id; + + /** + * 版本 + */ + @Version + @Column(name = "version") + private Integer version; + + /** + * 文件编号 + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "uuid") + private String uuid; + + /** + * 文件名称 + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "name") + private String name; + + /** + * 文件类型 + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "type") + private String type; + + /** + * 物理文件编号 + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "physical_uuid") + private String physicalUuid; + + /** + * 创建时间 + */ + @NotNull + @Column(name = "create_time") + @Temporal(TemporalType.TIMESTAMP) + @DateTimeFormat(style = "M-") + private Date createTime; + + /** + * 修改时间 + */ + @NotNull + @Column(name = "modified_time") + @Temporal(TemporalType.TIMESTAMP) + @DateTimeFormat(style = "M-") + private Date modifiedTime; + + /** + * 元数据,JSON格式 + */ + @Size(max = 1024) + @Column(name = "metadata") + private String metadata; + + /** + * 文件长度,单位:字节 + */ + @Column(name = "length") + private Long length; + + /** + * 文件标签,版本 + */ + @Size(max = 32) + @Column(name = "tag") + private String tag; + + /** + * 逻辑存储区名称 + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "bucket_name") + private String bucketName; + + /** + * 是否公开 + */ + @Column(name = "open") + private Boolean open; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getPhysicalUuid() { + return physicalUuid; + } + + public void setPhysicalUuid(String physicalUuid) { + this.physicalUuid = physicalUuid; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getModifiedTime() { + return modifiedTime; + } + + public void setModifiedTime(Date modifiedTime) { + this.modifiedTime = modifiedTime; + } + + public String getMetadata() { + return metadata; + } + + public void setMetadata(String metadata) { + this.metadata = metadata; + } + + public Long getLength() { + return length; + } + + public void setLength(Long length) { + this.length = length; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + public String getBucketName() { + return bucketName; + } + + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } + + public Boolean getOpen() { + return open; + } + + public void setOpen(Boolean open) { + this.open = open; + } + + @Override + public String toString() { + return "LogicalFile [id=" + id + ", version=" + version + ", uuid=" + uuid + ", name=" + name + ", type=" + type + + ", physicalUuid=" + physicalUuid + ", createTime=" + createTime + ", modifiedTime=" + modifiedTime + + ", metadata=" + metadata + ", length=" + length + ", tag=" + tag + ", bucketName=" + bucketName + + ", open=" + open + "]"; + } + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/PhysicalFile.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/PhysicalFile.java new file mode 100644 index 0000000..f90db49 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/PhysicalFile.java @@ -0,0 +1,205 @@ +package com.sinoparasoft.storage.domain; + +import org.springframework.format.annotation.DateTimeFormat; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Date; + +/** + * 物理文件实体类 + * + * @author 袁涛 + * @date 2017.10.26 + */ +@Entity +@Table(name = "physical_file") +public class PhysicalFile { + /** + * 编号 + */ + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id") + private Long id; + + /** + * 版本 + */ + @Version + @Column(name = "version") + private Integer version; + + /** + * 文件编号 + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "uuid") + private String uuid; + + /** + * 元数据,JSON格式 + */ + @Size(max = 4096) + @Column(name = "metadata") + private String metadata; + + /** + * 文件MD5 + */ + @Size(max = 64) + @Column(name = "md5") + private String md5; + + /** + * 文件SHA + */ + @Size(max = 64) + @Column(name = "sha") + private String sha; + + /** + * 物理文件块数 + */ + @NotNull + @Column(name = "tiles") + private Integer tiles; + + /** + * 创建时间 + */ + @NotNull + @Column(name = "create_time") + @Temporal(TemporalType.TIMESTAMP) + @DateTimeFormat(style = "M-") + private Date createTime; + + /** + * 修改时间 + */ + @NotNull + @Column(name = "modified_time") + @Temporal(TemporalType.TIMESTAMP) + @DateTimeFormat(style = "M-") + private Date modifiedTime; + + /** + * 文件长度,单位:字节 + */ + @Column(name = "length") + private Long length; + + /** + * 校验文件是否健康 + */ + @NotNull + @Column(name = "healthy") + private Boolean healthy; + + /** + * 校验时间 + */ + @NotNull + @Column(name = "check_time") + @Temporal(TemporalType.TIMESTAMP) + @DateTimeFormat(style = "M-") + private Date checkTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getMd5() { + return md5; + } + + public void setMd5(String md5) { + this.md5 = md5; + } + + public String getSha() { + return sha; + } + + public void setSha(String sha) { + this.sha = sha; + } + + public Integer getTiles() { + return tiles; + } + + public void setTiles(Integer tiles) { + this.tiles = tiles; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getModifiedTime() { + return modifiedTime; + } + + public void setModifiedTime(Date modifiedTime) { + this.modifiedTime = modifiedTime; + } + + public Long getLength() { + return length; + } + + public void setLength(Long length) { + this.length = length; + } + + public Boolean getHealthy() { + return healthy; + } + + public void setHealthy(Boolean healthy) { + this.healthy = healthy; + } + + public Date getCheckTime() { + return checkTime; + } + + public void setCheckTime(Date checkTime) { + this.checkTime = checkTime; + } + + @Override + public String toString() { + return "PhysicalFile [id=" + id + ", version=" + version + ", uuid=" + uuid + ", md5=" + md5 + ", sha=" + sha + + ", tiles=" + tiles + ", createTime=" + createTime + ", modifiedTime=" + modifiedTime + ", length=" + + length + ", healthy=" + healthy + ", checkTime=" + checkTime + "]"; + } + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/PhysicalTileFile.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/PhysicalTileFile.java new file mode 100644 index 0000000..45d177e --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/PhysicalTileFile.java @@ -0,0 +1,250 @@ +package com.sinoparasoft.storage.domain; + +import org.springframework.format.annotation.DateTimeFormat; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Date; + +/** + * 物理分块文件实体类 + * + * @author 袁涛 + * @date 2017.11.09 + */ +@Entity +@Table(name = "physical_tile_file") +public class PhysicalTileFile { + /** + * 编号 + */ + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id") + private Long id; + + /** + * 版本 + */ + @Version + @Column(name = "version") + private Integer version; + + /** + * 文件编号 + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "uuid") + private String uuid; + + /** + * 物理文件编号 + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "physical_uuid") + private String physicalUuid; + + /** + * 物理分块文件序号 + */ + @NotNull + @Column(name = "tile") + private Integer tile; + + /** + * 文件路径 + */ + @NotNull + @Size(min = 1, max = 256) + @Column(name = "path") + private String path; + + /** + * 文件MD5 + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "md5") + private String md5; + + /** + * 文件SHA + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "sha") + private String sha; + + /** + * 创建时间 + */ + @NotNull + @Column(name = "create_time") + @Temporal(TemporalType.TIMESTAMP) + @DateTimeFormat(style = "M-") + private Date createTime; + + /** + * 修改时间 + */ + @NotNull + @Column(name = "modified_time") + @Temporal(TemporalType.TIMESTAMP) + @DateTimeFormat(style = "M-") + private Date modifiedTime; + + /** + * 文件长度,单位:字节 + */ + @NotNull + @Column(name = "length") + private Long length; + + /** + * 存储区编号 + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "storage_region_uuid") + private String storageRegionUuid; + + /** + * 校验文件是否健康 + */ + @NotNull + @Column(name = "healthy") + private Boolean healthy; + + /** + * 校验时间 + */ + @NotNull + @Column(name = "check_time") + @Temporal(TemporalType.TIMESTAMP) + @DateTimeFormat(style = "M-") + private Date checkTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getPhysicalUuid() { + return physicalUuid; + } + + public void setPhysicalUuid(String physicalUuid) { + this.physicalUuid = physicalUuid; + } + + public Integer getTile() { + return tile; + } + + public void setTile(Integer tile) { + this.tile = tile; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getMd5() { + return md5; + } + + public void setMd5(String md5) { + this.md5 = md5; + } + + public String getSha() { + return sha; + } + + public void setSha(String sha) { + this.sha = sha; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getModifiedTime() { + return modifiedTime; + } + + public void setModifiedTime(Date modifiedTime) { + this.modifiedTime = modifiedTime; + } + + public Long getLength() { + return length; + } + + public void setLength(Long length) { + this.length = length; + } + + public String getStorageRegionUuid() { + return storageRegionUuid; + } + + public void setStorageRegionUuid(String storageRegionUuid) { + this.storageRegionUuid = storageRegionUuid; + } + + public Boolean getHealthy() { + return healthy; + } + + public void setHealthy(Boolean healthy) { + this.healthy = healthy; + } + + public Date getCheckTime() { + return checkTime; + } + + public void setCheckTime(Date checkTime) { + this.checkTime = checkTime; + } + + @Override + public String toString() { + return "PhysicalTileFile [id=" + id + ", version=" + version + ", uuid=" + uuid + ", physicalUuid=" + + physicalUuid + ", tile=" + tile + ", path=" + path + ", md5=" + md5 + ", sha=" + sha + ", createTime=" + + createTime + ", modifiedTime=" + modifiedTime + ", length=" + length + ", storageRegionUuid=" + + storageRegionUuid + ", healthy=" + healthy + ", checkTime=" + checkTime + "]"; + } + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/StorageRegion.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/StorageRegion.java new file mode 100644 index 0000000..7343089 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/domain/StorageRegion.java @@ -0,0 +1,223 @@ +package com.sinoparasoft.storage.domain; + +import org.springframework.format.annotation.DateTimeFormat; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Date; + +/** + * 存储区实体类 + * + * @author 袁涛 + * @date 2017.10.26 + */ +@Entity +@Table(name = "storage_region") +public class StorageRegion { + /** + * 编号 + */ + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id") + private Long id; + + /** + * 版本 + */ + @Version + @Column(name = "version") + private Integer version; + + /** + * 存储区编号 + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "uuid") + private String uuid; + + /** + * 存储区名称 + */ + @NotNull + @Size(min = 1, max = 64) + @Column(name = "name") + private String name; + + /** + * 存储区描述 + */ + @Size(max = 64) + @Column(name = "description") + private String description; + + /** + * 存储区路径 + */ + @NotNull + @Size(min = 1, max = 256) + @Column(name = "path") + private String path; + + /** + * 存储区总容量,单位:字节 + */ + @NotNull + @Column(name = "total_size") + private Long totalSize; + + /** + * 存储区已用容量,单位:字节 + */ + @NotNull + @Column(name = "used_size") + private Long usedSize; + + /** + * 存储区可用容量,单位:字节 + */ + @NotNull + @Column(name = "available_size") + private Long availableSize; + + /** + * 检查存储区是否健康 + */ + @NotNull + @Column(name = "healthy") + private Boolean healthy; + + /** + * 创建时间 + */ + @NotNull + @Column(name = "create_time") + @Temporal(TemporalType.TIMESTAMP) + @DateTimeFormat(style = "M-") + private Date createTime; + + /** + * 修改时间 + */ + @NotNull + @Column(name = "modified_time") + @Temporal(TemporalType.TIMESTAMP) + @DateTimeFormat(style = "M-") + private Date modifiedTime; + + /** + * 检查时间 + */ + @NotNull + @Column(name = "check_time") + @Temporal(TemporalType.TIMESTAMP) + @DateTimeFormat(style = "M-") + private Date checkTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public Long getTotalSize() { + return totalSize; + } + + public void setTotalSize(Long totalSize) { + this.totalSize = totalSize; + } + + public Long getUsedSize() { + return usedSize; + } + + public void setUsedSize(Long usedSize) { + this.usedSize = usedSize; + } + + public Long getAvailableSize() { + return availableSize; + } + + public void setAvailableSize(Long availableSize) { + this.availableSize = availableSize; + } + + public Boolean getHealthy() { + return healthy; + } + + public void setHealthy(Boolean healthy) { + this.healthy = healthy; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getModifiedTime() { + return modifiedTime; + } + + public void setModifiedTime(Date modifiedTime) { + this.modifiedTime = modifiedTime; + } + + public Date getCheckTime() { + return checkTime; + } + + public void setCheckTime(Date checkTime) { + this.checkTime = checkTime; + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/BucketQueryRequest.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/BucketQueryRequest.java new file mode 100644 index 0000000..792a11f --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/BucketQueryRequest.java @@ -0,0 +1,23 @@ +package com.sinoparasoft.storage.model; + +import io.swagger.annotations.ApiModelProperty; + +/** + * 逻辑存储区查询条件 + * + * @author 袁涛 + * @date 2018.09.14 + */ +public class BucketQueryRequest { + + @ApiModelProperty(value = "逻辑存储区名称") + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/DataTableQuery.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/DataTableQuery.java new file mode 100644 index 0000000..0e2845a --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/DataTableQuery.java @@ -0,0 +1,81 @@ +package com.sinoparasoft.storage.model; + +/** + * JQuery dataTables 查询参数类 + * + * @author 袁涛 + * @date 2017.09.29 + */ +public class DataTableQuery { + /** + * 起始记录 + */ + private Integer firstResult; + + /** + * 最大记录数 + */ + private Integer maxResults; + + /** + * 全局搜索字段 + */ + private String search; + + /** + * 排序字段名称 + */ + private String sortFieldName; + + /** + * 升序ASC或降序DESC + */ + private String sortOrder; + + public Integer getFirstResult() { + return firstResult; + } + + public void setFirstResult(Integer firstResult) { + this.firstResult = firstResult; + } + + public Integer getMaxResults() { + return maxResults; + } + + public void setMaxResults(Integer maxResults) { + this.maxResults = maxResults; + } + + public String getSearch() { + return search; + } + + public void setSearch(String search) { + this.search = search; + } + + public String getSortFieldName() { + return sortFieldName; + } + + public void setSortFieldName(String sortFieldName) { + this.sortFieldName = sortFieldName; + } + + public String getSortOrder() { + return sortOrder; + } + + public void setSortOrder(String sortOrder) { + this.sortOrder = sortOrder; + } + + @Override + public String toString() { + return "DataTableQuery [firstResult=" + firstResult + ", maxResults=" + maxResults + ", search=" + search + + ", sortFieldName=" + sortFieldName + ", sortOrder=" + sortOrder + "]"; + } + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/FileBlockCreateRequest.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/FileBlockCreateRequest.java new file mode 100644 index 0000000..6a3f997 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/FileBlockCreateRequest.java @@ -0,0 +1,105 @@ +package com.sinoparasoft.storage.model; + +import io.swagger.annotations.ApiModelProperty; +import org.springframework.web.multipart.MultipartFile; + +/** + * 文件分块上传请求 + * + * @author 袁涛 + * @date 2018.09.14 + */ +public class FileBlockCreateRequest { + /** + * 逻辑存储区名称 + */ + @ApiModelProperty(value = "逻辑存储区名称") + private String bucketName; + /** + * 文件内容 + */ + @ApiModelProperty(value = "文件内容") + private MultipartFile file; + /** + * 逻辑文件编号 + */ + @ApiModelProperty(value = "逻辑文件编号") + private String uuid; + /** + * 逻辑文件名称 + */ + @ApiModelProperty(value = "逻辑文件名称") + private String name; + /** + * 逻辑文件长度 + */ + @ApiModelProperty(value = "逻辑文件长度") + private Long length; + /** + * 逻辑文件分块序号 + */ + @ApiModelProperty(value = "逻辑文件分块序号") + private Integer chunk; + /** + * 逻辑文件分块数量 + */ + @ApiModelProperty(value = "逻辑文件分块数量") + private Integer chunks; + + public String getBucketName() { + return bucketName; + } + + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } + + public MultipartFile getFile() { + return file; + } + + public void setFile(MultipartFile file) { + this.file = file; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Long getLength() { + return length; + } + + public void setLength(Long length) { + this.length = length; + } + + public Integer getChunk() { + return chunk; + } + + public void setChunk(Integer chunk) { + this.chunk = chunk; + } + + public Integer getChunks() { + return chunks; + } + + public void setChunks(Integer chunks) { + this.chunks = chunks; + } + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/FileCreateRequest.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/FileCreateRequest.java new file mode 100644 index 0000000..c98eb46 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/FileCreateRequest.java @@ -0,0 +1,39 @@ +package com.sinoparasoft.storage.model; + +import io.swagger.annotations.ApiModelProperty; +import org.springframework.web.multipart.MultipartFile; + +/** + * 文件上传请求 + * + * @author 袁涛 + * @date 2018.09.14 + */ +public class FileCreateRequest { + /** + * 逻辑存储区名称 + */ + @ApiModelProperty(value = "逻辑存储区名称") + private String bucketName; + /** + * 文件数据 + */ + @ApiModelProperty(value = "文件数据") + private MultipartFile file; + + public String getBucketName() { + return bucketName; + } + + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } + + public MultipartFile getFile() { + return file; + } + + public void setFile(MultipartFile file) { + this.file = file; + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/FileCreateResponse.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/FileCreateResponse.java new file mode 100644 index 0000000..8e2a99f --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/FileCreateResponse.java @@ -0,0 +1,41 @@ +package com.sinoparasoft.storage.model; + +/** + * 文件上传响应类 + * + * @author 袁涛 + * @date 2017.10.16 + */ +public class FileCreateResponse { + /** + * 响应状态,是否成功 + */ + private Boolean status; + + /** + * 文件编号 + */ + private String uuid; + + public Boolean getStatus() { + return status; + } + + public void setStatus(Boolean status) { + this.status = status; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + @Override + public String toString() { + return "FileCreateResponse [status=" + status + ", uuid=" + uuid + "]"; + } + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/LogicalFileQueryRequest.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/LogicalFileQueryRequest.java new file mode 100644 index 0000000..33c4df5 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/LogicalFileQueryRequest.java @@ -0,0 +1,34 @@ +package com.sinoparasoft.storage.model; + +import io.swagger.annotations.ApiModelProperty; + +/** + * 文件查询条件 + * + * @author 袁涛 + * @date 2018.09.14 + */ +public class LogicalFileQueryRequest { + + @ApiModelProperty(value = "文件名称") + private String name; + + @ApiModelProperty(value = "逻辑存储区名称") + private String bucketName; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getBucketName() { + return bucketName; + } + + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/Metadata.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/Metadata.java new file mode 100644 index 0000000..b290c0d --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/Metadata.java @@ -0,0 +1,87 @@ +package com.sinoparasoft.storage.model; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Date; + +/** + * 文件元数据类 + * + * @author 袁涛 + * @date 2017.10.16 + */ +public class Metadata { + /** + * 文件名称 + */ + private String name; + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss") + @JsonProperty("create_time") + private Date createTime; + /** + * 修改时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss") + @JsonProperty("modified_time") + private Date modifiedTime; + /** + * 文件长度,单位:字节 + */ + private Long length; + + /** + * 文件标签,版本 + */ + private String tag; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getModifiedTime() { + return modifiedTime; + } + + public void setModifiedTime(Date modifiedTime) { + this.modifiedTime = modifiedTime; + } + + public Long getLength() { + return length; + } + + public void setLength(Long length) { + this.length = length; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + @Override + public String toString() { + return "Metadata [name=" + name + ", createTime=" + createTime + ", modifiedTime=" + modifiedTime + ", length=" + + length + ", tag=" + tag + "]"; + } + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/Response.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/Response.java new file mode 100644 index 0000000..ef1243c --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/Response.java @@ -0,0 +1,28 @@ +package com.sinoparasoft.storage.model; + +import io.swagger.annotations.ApiModelProperty; + +/** + * 简单响应类 + * + * @author 袁涛 + * + */ +public class Response { + + @ApiModelProperty(value = "内容") + private Object content; + + public Response(Object content) { + this.content = content; + } + + public Object getContent() { + return content; + } + + public void setContent(Object content) { + this.content = content; + } + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/StorageRegionQueryRequest.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/StorageRegionQueryRequest.java new file mode 100644 index 0000000..1d87c02 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/StorageRegionQueryRequest.java @@ -0,0 +1,23 @@ +package com.sinoparasoft.storage.model; + +import io.swagger.annotations.ApiModelProperty; + +/** + * 物理存储区查询条件 + * + * @author 袁涛 + * @date 2018.09.13 + */ +public class StorageRegionQueryRequest { + + @ApiModelProperty(value = "物理存储区名称") + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/UuidCreateResponse.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/UuidCreateResponse.java new file mode 100644 index 0000000..2bb4735 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/model/UuidCreateResponse.java @@ -0,0 +1,40 @@ +package com.sinoparasoft.storage.model; + +/** + * UUID创建响应类 + * + * @author 袁涛 + * @date 2017.11.13 + */ +public class UuidCreateResponse { + /** + * 响应状态,是否成功 + */ + private Boolean status; + + /** + * 文件编号 + */ + private String uuid; + + public Boolean getStatus() { + return status; + } + + public void setStatus(Boolean status) { + this.status = status; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + @Override + public String toString() { + return "UuidCreateResponse [status=" + status + ", uuid=" + uuid + "]"; + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/BucketRepository.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/BucketRepository.java new file mode 100644 index 0000000..0739232 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/BucketRepository.java @@ -0,0 +1,72 @@ +package com.sinoparasoft.storage.repository; + +import com.sinoparasoft.storage.domain.Bucket; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * 逻辑存储区管理接口 + * + * @author 袁涛 + * @date 2018.06.07 + */ +public interface BucketRepository extends JpaRepository { + /** + * 根据逻辑存储区名称统计逻辑存储区的个数 + * + * @param name + * 逻辑存储区名称 + * @return 逻辑存储区的个数 + */ + public Long countByName(String name); + + /** + * 根据逻辑存储区名称查询逻辑存储区的信息 + * + * @param name + * 逻辑存储区名称 + * @return 逻辑存储区信息 + */ + public Bucket findFirstByName(String name); + + /** + * 根据逻辑存储区编号统计逻辑存储区的个数 + * + * @param id + * 逻辑存储区编号 + * @return 逻辑存储区的个数 + */ + public Long countById(Long id); + + /** + * 根据逻辑存储区编号查询逻辑存储区的信息 + * + * @param id + * 逻辑存储区编号 + * @return 逻辑存储区信息 + */ + public Bucket findFirstById(Long id); + + /** + * 根据逻辑存储区名称查询存储区列表 + * + * @param name + * 逻辑存储区名称 + * @param pageable + * 分页信息 + * @return 逻辑存储区列表 + */ + public Page findByNameLike(String name, Pageable pageable); + + /** + * 根据逻辑存储区编号和逻辑存储区名称统计逻辑存储区个数 + * + * @param id + * 逻辑存储区编号 + * @param name + * 逻辑存储区名称 + * @return 逻辑存储区个数 + */ + public Long countByIdNotAndName(Long id, String name); +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/HistoryFileRepository.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/HistoryFileRepository.java new file mode 100644 index 0000000..3482c22 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/HistoryFileRepository.java @@ -0,0 +1,14 @@ +package com.sinoparasoft.storage.repository; + +import com.sinoparasoft.storage.domain.HistoryFile; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * 历史文件管理接口 + * + * @author 袁涛 + * @date 2017.10.26 + */ +public interface HistoryFileRepository extends JpaRepository { + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/LogicalFileRepository.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/LogicalFileRepository.java new file mode 100644 index 0000000..178d091 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/LogicalFileRepository.java @@ -0,0 +1,64 @@ +package com.sinoparasoft.storage.repository; + +import com.sinoparasoft.storage.domain.LogicalFile; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +/** + * 逻辑文件管理接口 + * + * @author 袁涛 + * @date 2017.10.26 + */ +public interface LogicalFileRepository extends JpaRepository { + + /** + * 根据文件编号统计逻辑文件的个数 + * + * @param uuid + * 文件编号 + * @return 逻辑文件的个数 + */ + public Long countByUuid(String uuid); + + /** + * 根据文件编号查询逻辑文件信息 + * + * @param uuid + * 文件编号 + * @return 逻辑文件信息 + */ + public LogicalFile findFirstByUuid(String uuid); + + /** + * 根据文件名称查询文件列表 + * + * @param name + * 文件名称 + * @param pageable + * 分页信息 + * @return 文件列表 + */ + public Page findByNameLike(String name, Pageable pageable); + + /** + * 根据逻辑存储区名称统计逻辑文件的个数 + * + * @param bucketName + * 逻辑存储区名称 + * @return 逻辑文件的个数 + */ + public Long countByBucketName(String bucketName); + + /** + * 根据逻辑存储区名称统计逻辑文件的大小 + * + * @param bucketName + * 逻辑存储区大小 + * @return 逻辑文件的个数 + */ + @Query("SELECT SUM(file.length) FROM LogicalFile file WHERE file.bucketName = ?1") + public Long sumLengthByBucketName(String bucketName); +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/PhysicalFileRepository.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/PhysicalFileRepository.java new file mode 100644 index 0000000..5b99dbb --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/PhysicalFileRepository.java @@ -0,0 +1,53 @@ +package com.sinoparasoft.storage.repository; + +import com.sinoparasoft.storage.domain.PhysicalFile; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * 物理文件管理接口 + * + * @author 袁涛 + * @date 2017.10.26 + */ +public interface PhysicalFileRepository extends JpaRepository { + /** + * 根据文件MD5和SHA统计物理文件个数 + * + * @param md5 + * 文件MD5 + * @param sha + * 文件SHA + * @return 物理文件个数 + */ + public Long countByMd5AndSha(String md5, String sha); + + /** + * 根据文件MD5和SHA查找物理文件信息 + * + * @param md5 + * 文件MD5 + * @param sha + * 文件SHA + * @return 物理文件信息 + */ + public PhysicalFile findFirstByMd5AndSha(String md5, String sha); + + /** + * 根据文件编号统计物理文件的个数 + * + * @param uuid + * 文件编号 + * @return 物理文件的个数 + */ + public Long countByUuid(String uuid); + + /** + * 根据文件编号查询物理文件信息 + * + * @param uuid + * 文件编号 + * @return 物理文件信息 + */ + public PhysicalFile findFirstByUuid(String uuid); + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/PhysicalTileFileRepository.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/PhysicalTileFileRepository.java new file mode 100644 index 0000000..bc4c25a --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/PhysicalTileFileRepository.java @@ -0,0 +1,81 @@ +package com.sinoparasoft.storage.repository; + +import com.sinoparasoft.storage.domain.PhysicalTileFile; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +/** + * 物理分块文件管理接口 + * + * @author 袁涛 + * @date 2017.11.09 + */ +public interface PhysicalTileFileRepository extends JpaRepository { + /** + * 根据文件MD5和SHA统计物理分块文件个数 + * + * @param md5 + * 物理分块文件MD5 + * @param sha + * 物理分块文件SHA + * @return 物理文件个数 + */ + public Long countByMd5AndSha(String md5, String sha); + + /** + * 根据文件MD5和SHA查找物理分块文件信息 + * + * @param md5 + * 物理分块文件MD5 + * @param sha + * 物理分块文件SHA + * @return 物理分块文件信息 + */ + public PhysicalTileFile findFirstByMd5AndSha(String md5, String sha); + + /** + * 根据文件编号统计物理分块文件的个数 + * + * @param uuid + * 物理分块文件编号 + * @return 物理分块文件的个数 + */ + public Long countByUuid(String uuid); + + /** + * 根据文件编号查询物理分块文件信息 + * + * @param uuid + * 物理分块文件编号 + * @return 物理分块文件信息 + */ + public PhysicalTileFile findFirstByUuid(String uuid); + + /** + * 根据物理文件编号统计物理分块文件的个数 + * + * @param uuid + * 物理文件编号 + * @return 物理分块文件的个数 + */ + public Long countByPhysicalUuid(String physicalUuid); + + /** + * 根据物理文件编号查询物理分块文件列表 + * + * @param uuid + * 物理文件编号 + * @return 物理分块文件列表 + */ + public List findByPhysicalUuidOrderByTile(String physicalUuid); + + /** + * 根据存储区编号统计物理分块文件的个数 + * + * @param storageRegionUuid + * 存储区编号 + * @return 物理分块文件的个数 + */ + public Long countByStorageRegionUuid(String storageRegionUuid); +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/StorageRegionRepository.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/StorageRegionRepository.java new file mode 100644 index 0000000..f5d9fb9 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/repository/StorageRegionRepository.java @@ -0,0 +1,99 @@ +package com.sinoparasoft.storage.repository; + +import com.sinoparasoft.storage.domain.StorageRegion; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +/** + * 物理存储区管理接口 + * + * @author 袁涛 + * @date 2017.10.26 + */ +public interface StorageRegionRepository extends JpaRepository { + + /** + * 根据可用空间和存储状态统计物理存储区的个数 + * + * @param availableSize + * 物理存储区可用容量,单位:字节 + * @param healthy + * 物理存储区是否健康 + * @return 物理存储区的个数 + */ + public Long countByAvailableSizeGreaterThanAndHealthy(Long availableSize, Boolean healthy); + + /** + * 根据可用空间和存储状态查询物理存储区列表 + * + * @param availableSize + * 物理存储区可用容量,单位:字节 + * @param healthy + * 物理存储区是否健康 + * @return 物理存储区列表 + */ + public List findByAvailableSizeGreaterThanAndHealthy(Long availableSize, Boolean healthy); + + /** + * 根据物理存储区编号统计物理存储区的个数 + * + * @param uuid + * 物理存储区编号 + * @return 物理存储区的个数 + */ + public Long countByUuid(String uuid); + + /** + * 根据物理存储区编号查询物理存储区信息 + * + * @param uuid + * 物理存储区编号 + * @return 物理存储区信息 + */ + public StorageRegion findFirstByUuid(String uuid); + + /** + * 根据物理存储区路径查询物理存储区列表 + * + * @param path + * 物理存储区路径 + * @param pageable + * 分页信息 + * @return 物理存储区列表 + */ + public Page findByPathLike(String path, Pageable pageable); + + /** + * 根据物理存储区名称查询物理存储区列表 + * + * @param name + * 物理存储区名称 + * @param pageable + * 分页信息 + * @return 物理存储区列表 + */ + public Page findByNameLike(String name, Pageable pageable); + + /** + * 根据物理存储区名称统计物理存储区个数 + * + * @param name + * 物理存储区名称 + * @return 物理存储区个数 + */ + public Long countByName(String name); + + /** + * 根据物理存储区编号和物理存储区名称统计物理存储区个数 + * + * @param id + * 物理存储区编号 + * @param name + * 物理存储区名称 + * @return 物理存储区个数 + */ + public Long countByIdNotAndName(Long id, String name); +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/BucketService.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/BucketService.java new file mode 100644 index 0000000..2a5b919 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/BucketService.java @@ -0,0 +1,274 @@ +package com.sinoparasoft.storage.service; + +import com.sinoparasoft.storage.domain.Bucket; +import com.sinoparasoft.storage.model.BucketQueryRequest; +import com.sinoparasoft.storage.repository.BucketRepository; +import com.sinoparasoft.storage.repository.LogicalFileRepository; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.List; +import java.util.Optional; + +/** + * 逻辑存储区管理服务类 + * + * @author 袁涛 + * @date 2018.06.08 + */ +@Component +public class BucketService { + private static final Logger logger = LoggerFactory.getLogger(BucketService.class); + + /** + * 逻辑存储区管理接口 + */ + @Autowired + private BucketRepository bucketRepository; + + /** + * 逻辑文件管理接口 + */ + @Autowired + private LogicalFileRepository logicalFileRepository; + + /** + * 获取逻辑存储区列表 + * + * @param request + * 逻辑存储区查询请求 + * @param pageable + * 分页信息 + * @return 逻辑存储区列表 + */ + public Page findAll(BucketQueryRequest request, Pageable pageable) { + if (StringUtils.isBlank(request.getName())) { + // 逻辑存储区名称为空 + return this.bucketRepository.findAll(pageable); + } else { + // 逻辑存储区名称不为空 + String name = request.getName(); + if (!name.startsWith("%")) { + name = "%" + name; + } + if (!name.endsWith("%")) { + name = name + "%"; + } + return this.bucketRepository.findByNameLike(name, pageable); + } + } + + /** + * 根据逻辑存储区编号查询逻辑存储区信息 + * + * @param id + * 逻辑存储区编号 + * @return 逻辑存储区信息 + */ + public Bucket findById(Long id) { + Bucket retValue = null; + if (id == null) { + String message = "bucket id is null."; + logger.error(message); + throw new RuntimeException(message); + } + Optional query = this.bucketRepository.findById(id); + if (query.isPresent()) { + retValue = query.get(); + } else { + String message = "find bucket by id failed, id = " + id; + logger.error(message); + throw new RuntimeException(message); + } + return retValue; + } + + /** + * 新建逻辑存储区 + * + * @param request + * 逻辑存储区信息 + * @return 逻辑存储区信息 + */ + public Bucket create(Bucket request) { + // 检查参数 + if (StringUtils.isBlank(request.getName())) { + String message = "bucket name is null."; + logger.error(message); + throw new RuntimeException(message); + } + if (request.getTotalSize() == null || request.getTotalSize() < 0) { + String message = "bucket total size is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 检查逻辑存储区是否存在 + if (this.bucketRepository.countByName(request.getName()) > 0) { + String message = "create bucket failed, name already exists, name = " + request.getName(); + logger.error(message); + throw new RuntimeException(message); + } + // 写入数据库 + Bucket bucket = new Bucket(); + // 逻辑存储区名称 + bucket.setName(request.getName()); + // 逻辑存储区描述 + bucket.setDescription(request.getDescription()); + // 创建时间 + bucket.setCreateTime(new Date()); + // 修改时间 + bucket.setModifiedTime(new Date()); + // 元数据 + // 容量,单位:字节 + bucket.setTotalSize(request.getTotalSize()); + // 已使用容量,单位:字节 + bucket.setUsedSize(0L); + // 剩余容量,单位:字节 + bucket.setAvailableSize(request.getTotalSize()); + // 保存逻辑存储区信息 + this.bucketRepository.save(bucket); + + String message = "create bucket sucess, name = " + request.getName(); + logger.info(message); + + return bucket; + } + + /** + * 删除逻辑存储区 + * + * @param id + * 逻辑存储区编号 + */ + public void delete(Long id) { + // 检查参数 + if (id == null) { + String message = "delete bucket failed, id is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 查找逻辑存储区 + Optional query = this.bucketRepository.findById(id); + if (query.isPresent()) { + // 逻辑存储区存在,在数据库中删除记录 + Bucket bucket = query.get(); + // 逻辑存储区上有文件,不能删除,要删除必须先清空逻辑存储区上的文件 + if (this.logicalFileRepository.countByBucketName(bucket.getName()) > 0) { + String message = "bucket has files, delete must clear files first, bucket id = " + id; + logger.error(message); + throw new RuntimeException(message); + } else { + this.bucketRepository.delete(bucket); + String message = "delete bucket sucess, bucket id = " + id; + logger.info(message); + } + } else { + // 逻辑存储区不存在 + String message = "delete bucket failed, bucket does not exist, id = " + id; + logger.error(message); + throw new RuntimeException(message); + } + } + + /** + * 批量删除逻辑存储区 + * + * @param ids + * 逻辑存储区编号列表 + */ + public void delete(List ids) { + if (ids != null && ids.size() > 0) { + for (Long id : ids) { + this.delete(id); + } + } + } + + /** + * 更新逻辑存储区 + * + * @param request + * 逻辑存储区信息 + */ + public void update(Bucket request) { + // 检查参数 + if (request.getId() == null) { + String message = "update bucket failed, id is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 查找逻辑存储区 + Optional query = this.bucketRepository.findById(request.getId()); + if (query.isPresent()) { + // 逻辑存储区存在 + Bucket bucket = query.get(); + // 字段非空才更新 + if (!StringUtils.isBlank(request.getName())) { + // 查询逻辑存储区是否重名 + if (this.bucketRepository.countByIdNotAndName(request.getId(), request.getName()) > 0) { + String message = "update bucket failed, name already exists, name = " + request.getName(); + logger.error(message); + throw new RuntimeException(message); + } else { + // 逻辑存储区名称 + bucket.setName(request.getName()); + } + } + if (!StringUtils.isBlank(request.getDescription())) { + // 逻辑存储区描述 + bucket.setDescription(request.getDescription()); + } + if (request.getTotalSize() != null && request.getTotalSize() > 0) { + // 容量,单位:字节 + bucket.setTotalSize(request.getTotalSize()); + } + // 修改时间 + bucket.setModifiedTime(new Date()); + this.bucketRepository.save(bucket); + String message = "update bucket information sucess, bucket name = " + request.getName(); + logger.info(message); + } else { + // 逻辑存储区不存在 + String message = "update bucket failed, bucket does not exist, id = " + request.getId(); + logger.error(message); + throw new RuntimeException(message); + } + } + + /** + * 定期检查逻辑存储区容量使用情况,每隔一小时检查一次 + */ + @Scheduled(cron = "0 0 0/1 * * ? ") + public void check() { + Long start = System.currentTimeMillis(); + if (this.bucketRepository.count() > 0) { + List buckets = this.bucketRepository.findAll(); + if (buckets != null && buckets.size() > 0) { + for (Bucket bucket : buckets) { + // 逻辑存储区已用容量,单位:字节 + Long usedSize = this.logicalFileRepository.sumLengthByBucketName(bucket.getName()); + if (usedSize == null) { + usedSize = 0L; + } + bucket.setUsedSize(usedSize); + // 逻辑存储区可用容量,单位:字节 + Long availableSize = bucket.getTotalSize() - bucket.getUsedSize(); + bucket.setAvailableSize(availableSize); + // 检查时间 + bucket.setModifiedTime(new Date()); + this.bucketRepository.save(bucket); + } + } + } + Long end = System.currentTimeMillis(); + String msg = "check bucket use " + (end - start) + " ms."; + logger.info(msg); + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/FileService.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/FileService.java new file mode 100644 index 0000000..6d63f55 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/FileService.java @@ -0,0 +1,951 @@ +package com.sinoparasoft.storage.service; + +import com.sinoparasoft.storage.domain.Bucket; +import com.sinoparasoft.storage.domain.LogicalFile; +import com.sinoparasoft.storage.domain.PhysicalFile; +import com.sinoparasoft.storage.domain.PhysicalTileFile; +import com.sinoparasoft.storage.model.FileBlockCreateRequest; +import com.sinoparasoft.storage.model.FileCreateRequest; +import com.sinoparasoft.storage.model.LogicalFileQueryRequest; +import com.sinoparasoft.storage.repository.BucketRepository; +import com.sinoparasoft.storage.repository.LogicalFileRepository; +import com.sinoparasoft.storage.repository.PhysicalFileRepository; +import com.sinoparasoft.storage.repository.PhysicalTileFileRepository; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Zip; +import org.apache.tools.ant.types.FileSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.InputStreamResource; +import org.springframework.core.io.Resource; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import java.io.*; +import java.net.URLEncoder; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.*; + +/** + * 数据分析任务服务类 + * + * @author 袁涛 + * @date 2017.10.16 + */ +@Component +public class FileService { + private static final Logger logger = LoggerFactory.getLogger(FileService.class); + + /** + * 物理文件管理接口 + */ + @Autowired + private PhysicalFileRepository physicalFileRepository; + + /** + * 物理分块文件管理接口 + */ + @Autowired + private PhysicalTileFileRepository physicalTileFileRepository; + + /** + * 逻辑文件管理接口 + */ + @Autowired + private LogicalFileRepository logicalFileRepository; + + /** + * 逻辑存储区管理接口 + */ + @Autowired + private BucketRepository bucketRepository; + + @Autowired + private PhysicalFileService physicalFileService; + + /** + * 文件服务中间目录地址 + */ + @Value("${spring.servlet.multipart.location}") + private String location; + + /** + * 获取逻辑文件列表 + * + * @param request + * 逻辑文件查询请求 + * @param pageable + * 分页信息 + * @return 逻辑文件列表 + */ + public Page findAll(LogicalFileQueryRequest request, Pageable pageable) { + if (StringUtils.isBlank(request.getName())) { + // 应用系统名称为空 + return this.logicalFileRepository.findAll(pageable); + } else { + // 应用系统名称不为空 + String name = request.getName(); + if (!name.startsWith("%")) { + name = "%" + name; + } + if (!name.endsWith("%")) { + name = name + "%"; + } + return this.logicalFileRepository.findByNameLike(name, pageable); + } + } + + /** + * 根据逻辑文件编号查询逻辑文件信息 + * + * @param id + * 逻辑文件编号 + * @return 逻辑文件信息 + */ + public LogicalFile findById(Long id) { + LogicalFile retValue = null; + // 检查参数 + if (id == null) { + String message = "logical file id is null."; + logger.error(message); + throw new RuntimeException(message); + } + Optional query = this.logicalFileRepository.findById(id); + if (query.isPresent()) { + retValue = query.get(); + } else { + String message = "find logical file by id failed, id = " + id; + logger.error(message); + throw new RuntimeException(message); + } + return retValue; + } + + /** + * 根据逻辑文件编号查询逻辑文件信息 + * + * @param uuid + * 逻辑文件编号 + * @return 逻辑文件信息 + */ + public LogicalFile findByUuid(String uuid) { + LogicalFile retValue = null; + // 检查参数 + if (StringUtils.isBlank(uuid)) { + String message = "logical file uuid is null."; + logger.error(message); + throw new RuntimeException(message); + } + if (this.logicalFileRepository.countByUuid(uuid) > 0) { + retValue = this.logicalFileRepository.findFirstByUuid(uuid); + } else { + String message = "find logical file failed by uuid, uuid = " + uuid; + logger.error(message); + throw new RuntimeException(message); + } + + return retValue; + } + + /** + * 根据文件名称获取文件类型 + * + * @param fileName + * 文件名称 + * @return 文件类型 + */ + public String getFileType(String fileName) { + String retValue = "UNKNOWN"; + + if (fileName.contains(".") && fileName.endsWith(".") == false) { + String suffix = fileName.substring(fileName.lastIndexOf('.') + 1); + retValue = suffix.toUpperCase(); + } + + return retValue; + } + + /** + * 新建逻辑文件 + * + * @param request + * 新建逻辑文件请求 + * @return 逻辑文件信息 + */ + public LogicalFile create(FileBlockCreateRequest request) { + // 检查参数 + if (StringUtils.isBlank(request.getBucketName())) { + String message = "bucket name is null."; + logger.error(message); + throw new RuntimeException(message); + } + if (request.getFile() == null) { + String message = "file is null."; + logger.error(message); + throw new RuntimeException(message); + } + if (StringUtils.isBlank(request.getUuid())) { + String message = "file uuid is null."; + logger.error(message); + throw new RuntimeException(message); + } + if (StringUtils.isBlank(request.getName())) { + String message = "file name is null."; + logger.error(message); + throw new RuntimeException(message); + } + if (request.getLength() == null || request.getLength() < 0) { + String message = "file length is null or less than 0."; + logger.error(message); + throw new RuntimeException(message); + } + if (request.getChunk() == null || request.getChunk() < 0) { + String message = "file chunk is null or less than 0."; + logger.error(message); + throw new RuntimeException(message); + } + if (request.getChunks() == null || request.getChunks() < 0) { + String message = "file chunks is null or less than 0."; + logger.error(message); + throw new RuntimeException(message); + } + // 查询逻辑存储区信息 + if (this.bucketRepository.countByName(request.getBucketName()) == 0) { + String message = "find bucket name failed, bucket name = " + request.getBucketName(); + logger.error(message); + + throw new RuntimeException(message); + } + // 检查逻辑存储区的可用空间 + Bucket bucket = this.bucketRepository.findFirstByName(request.getBucketName()); + if (bucket.getAvailableSize() < 0) { + String message = "bucket available size is used up, need to extend bucket size, bucket name = " + + request.getBucketName(); + logger.error(message); + + throw new RuntimeException(message); + } + + LogicalFile logicalFile = null; + if (this.logicalFileRepository.countByUuid(request.getUuid()) > 0) { + logicalFile = this.logicalFileRepository.findFirstByUuid(request.getUuid()); + } else { + logicalFile = new LogicalFile(); + logicalFile.setUuid(request.getUuid()); + // 文件名称 + logicalFile.setName(request.getName()); + // 文件类型 + String type = this.getFileType(request.getName()); + logicalFile.setType(type); + // 物理文件编号 + String physicalUuid = UUID.randomUUID().toString(); + logicalFile.setPhysicalUuid(physicalUuid); + // 创建时间 + logicalFile.setCreateTime(new Date()); + // 修改时间 + logicalFile.setModifiedTime(new Date()); + // 文件长度,单位:字节 + logicalFile.setLength(request.getLength()); + // 逻辑存储区名称 + logicalFile.setBucketName(request.getBucketName()); + // 是否公开 + logicalFile.setOpen(false); + // 保存逻辑文件信息 + this.logicalFileRepository.save(logicalFile); + } + + // 创建物理文件 + this.physicalFileService.create(request.getUuid(), request.getChunk(), request.getChunks(), request.getFile()); + + String message = "create logical file sucess, name = " + request.getName(); + logger.info(message); + + return logicalFile; + } + + /** + * 新建逻辑文件 + * + * @param request + * 逻辑文件信息 + * @return 逻辑文件信息 + */ + public LogicalFile create(FileCreateRequest request) { + // 检查参数 + if (StringUtils.isBlank(request.getBucketName())) { + String message = "bucket name is null."; + logger.error(message); + throw new RuntimeException(message); + } + if (request.getFile() == null) { + String message = "file is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 新建逻辑文件块请求 + FileBlockCreateRequest fileBlockCreateRequest = new FileBlockCreateRequest(); + // 逻辑存储区名称 + fileBlockCreateRequest.setBucketName(request.getBucketName()); + // 文件内容 + fileBlockCreateRequest.setFile(request.getFile()); + // 逻辑文件编号 + String uuid = UUID.randomUUID().toString(); + fileBlockCreateRequest.setUuid(uuid); + // 逻辑文件名称 + fileBlockCreateRequest.setName(request.getFile().getOriginalFilename()); + // 逻辑文件长度 + fileBlockCreateRequest.setLength(request.getFile().getSize()); + // 逻辑文件分块序号 + fileBlockCreateRequest.setChunk(0); + // 逻辑文件分块数量 + fileBlockCreateRequest.setChunks(1); + + return this.create(fileBlockCreateRequest); + } + + /** + * 删除逻辑文件 + * + * @param id + * 逻辑文件编号 + */ + public void delete(Long id) { + // 检查参数 + if (id == null) { + String message = "delete logical file failed, id is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 查找逻辑文件 + Optional query = this.logicalFileRepository.findById(id); + if (query.isPresent()) { + // 逻辑文件存在,在数据库中删除记录 + LogicalFile file = query.get(); + this.logicalFileRepository.delete(file); + String message = "delete logical file sucess, logical file id = " + id; + logger.info(message); + } else { + // 逻辑文件不存在 + String message = "delete logical file failed, logical file does not exist, id = " + id; + logger.error(message); + throw new RuntimeException(message); + } + } + + /** + * 根据逻辑文件UUID编号删除逻辑文件 + * + * @param uuid + * 逻辑文件UUID编号 + */ + public void delete(String uuid) { + // 检查参数 + if (StringUtils.isBlank(uuid)) { + String message = "delete logical file failed, uuid is null."; + logger.error(message); + throw new RuntimeException(message); + } + if (this.logicalFileRepository.countByUuid(uuid) > 0) { + LogicalFile file = this.logicalFileRepository.findFirstByUuid(uuid); + this.logicalFileRepository.delete(file); + String message = "delete logical file sucess, logical file uuid = " + uuid; + logger.info(message); + } else { + String msg = "find logical file failed by uuid, uuid = " + uuid; + logger.error(msg); + } + } + + /** + * 批量删除逻辑文件 + * + * @param uuids + * 逻辑文件编号列表 + * @return 是否成功 + */ + public void delete(List uuids) { + if (uuids != null && uuids.size() > 0) { + for (String uuid : uuids) { + this.delete(uuid); + } + } + } + + /** + * 更新逻辑文件 + * + * @param request + * 逻辑文件信息 + */ + public void update(LogicalFile request) { + // 检查参数 + if (request.getId() == null) { + String message = "update logical file failed, id is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 查找逻辑文件 + Optional query = this.logicalFileRepository.findById(request.getId()); + if (query.isPresent()) { + // 逻辑文件存在 + LogicalFile file = query.get(); + // 字段非空才更新 + if (!StringUtils.isBlank(request.getName())) { + // 逻辑文件名称 + file.setName(request.getName()); + } + if (!StringUtils.isBlank(request.getType())) { + // 文件类型 + file.setType(request.getType()); + } + if (!StringUtils.isBlank(request.getMetadata())) { + // 元数据,JSON格式 + file.setMetadata(request.getMetadata()); + } + if (!StringUtils.isBlank(request.getTag())) { + // 文件标签,版本 + file.setTag(request.getTag()); + } + if (!StringUtils.isBlank(request.getBucketName())) { + // 逻辑存储区名称 + file.setBucketName(request.getBucketName()); + } + // 修改时间 + file.setModifiedTime(new Date()); + this.logicalFileRepository.save(file); + String message = "update logical file information sucess, logical file name = " + request.getName(); + logger.info(message); + } else { + // 逻辑文件不存在 + String message = "update logical file failed, logical file does not exist, id = " + request.getId(); + logger.error(message); + throw new RuntimeException(message); + } + } + + /** + * 下载逻辑文件 + * + * @param id + * 逻辑文件编号 + * @return + * @throws IOException + */ + public ResponseEntity download(HttpServletRequest request, Long id) throws IOException { + // 检查参数 + if (id == null) { + String message = "download logical file failed, id is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 查找逻辑文件 + Optional query = this.logicalFileRepository.findById(id); + if (query.isPresent()) { + LogicalFile logicalFile = query.get(); + // 检查物理文件是否存在 + if (this.physicalFileRepository.countByUuid(logicalFile.getPhysicalUuid()) == 0) { + // 物理文件不存在 + String message = "download logical file failed, logical file id = " + id; + message += ", find physical file by uuid failed, physical file uuid = " + logicalFile.getPhysicalUuid(); + logger.error(message); + throw new RuntimeException(message); + } + PhysicalFile physicalFile = this.physicalFileRepository.findFirstByUuid(logicalFile.getPhysicalUuid()); + // 创建协议头 + HttpHeaders headers = new HttpHeaders(); + headers.add("Content-Type", "application/octet-stream"); + headers.add("Cache-Control", "no-cache, no-store, must-revalidate"); + // 根据不同浏览器进行处理 + String agent = request.getHeader("User-Agent"); + if (agent.toLowerCase().contains("firefox")) { + headers.add("Content-Disposition", "attachment;fileName==?UTF-8?B?" + + Base64.getEncoder().encodeToString(logicalFile.getName().getBytes("utf-8")) + "?="); + } else { + headers.add("Content-Disposition", + "attachment;fileName=" + URLEncoder.encode(logicalFile.getName(), "utf-8")); + } + headers.add("Pragma", "no-cache"); + headers.add("Expires", "0"); + headers.add("charset", "utf-8"); + // 创建输出流 + ByteArrayOutputStream out = new ByteArrayOutputStream(); + // 输出文件 + List physicalTileFileList = this.physicalTileFileRepository + .findByPhysicalUuidOrderByTile(physicalFile.getUuid()); + for (PhysicalTileFile physicalTileFile : physicalTileFileList) { + Files.copy(Paths.get(physicalTileFile.getPath()), out); + } + Resource resource = new InputStreamResource(new ByteArrayInputStream(out.toByteArray())); + + return ResponseEntity.ok().headers(headers).contentLength(physicalFile.getLength()) + .contentType(MediaType.APPLICATION_OCTET_STREAM).body(resource); + } else { + // 逻辑文件不存在 + String message = "download logical file failed, logical file does not exist, id = " + id; + logger.error(message); + throw new RuntimeException(message); + } + } + + /** + * 下载逻辑文件 + * + * @param uuid + * 逻辑文件UUID编号 + * @return + * @throws IOException + */ + public ResponseEntity download(HttpServletRequest request, String uuid) throws IOException { + // 检查参数 + if (StringUtils.isBlank(uuid)) { + String message = "download logical file failed, uuid is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 检查逻辑文件是否存在 + if (this.logicalFileRepository.countByUuid(uuid) == 0) { + // 逻辑文件不存在 + String message = "download logical file failed, logical file does not exist, uuid = " + uuid; + logger.error(message); + throw new RuntimeException(message); + } + LogicalFile logicalFile = this.logicalFileRepository.findFirstByUuid(uuid); + // 检查物理文件是否存在 + if (this.physicalFileRepository.countByUuid(logicalFile.getPhysicalUuid()) == 0) { + // 物理文件不存在 + String message = "download logical file failed, logical file uuid = " + uuid; + message += ", find physical file by uuid failed, physical file uuid = " + logicalFile.getPhysicalUuid(); + logger.error(message); + throw new RuntimeException(message); + } + PhysicalFile physicalFile = this.physicalFileRepository.findFirstByUuid(logicalFile.getPhysicalUuid()); + // 创建协议头 + HttpHeaders headers = new HttpHeaders(); + headers.add("Content-Type", "application/octet-stream"); + headers.add("Cache-Control", "no-cache, no-store, must-revalidate"); + // 根据不同浏览器进行处理 + String agent = request.getHeader("User-Agent"); + if (agent.toLowerCase().contains("firefox")) { + headers.add("Content-Disposition", "attachment;fileName==?UTF-8?B?" + + Base64.getEncoder().encodeToString(logicalFile.getName().getBytes("utf-8")) + "?="); + } else { + headers.add("Content-Disposition", + "attachment;fileName=" + URLEncoder.encode(logicalFile.getName(), "utf-8")); + } + headers.add("Pragma", "no-cache"); + headers.add("Expires", "0"); + headers.add("charset", "utf-8"); + // 创建输出流 + ByteArrayOutputStream out = new ByteArrayOutputStream(); + // 输出文件 + List physicalTileFileList = this.physicalTileFileRepository + .findByPhysicalUuidOrderByTile(physicalFile.getUuid()); + for (PhysicalTileFile physicalTileFile : physicalTileFileList) { + Files.copy(Paths.get(physicalTileFile.getPath()), out); + } + Resource resource = new InputStreamResource(new ByteArrayInputStream(out.toByteArray())); + + return ResponseEntity.ok().headers(headers).contentLength(physicalFile.getLength()) + .contentType(MediaType.APPLICATION_OCTET_STREAM).body(resource); + } + + /** + * 浏览逻辑文件 + * + * @param uuid + * 逻辑文件UUID编号 + * @return + * @throws IOException + */ + public ResponseEntity view(HttpServletRequest request, String uuid) throws IOException { + // 检查参数 + if (StringUtils.isBlank(uuid)) { + String message = "view logical file failed, uuid is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 检查逻辑文件是否存在 + if (this.logicalFileRepository.countByUuid(uuid) == 0) { + // 逻辑文件不存在 + String message = "view logical file failed, logical file does not exist, uuid = " + uuid; + logger.error(message); + throw new RuntimeException(message); + } + LogicalFile logicalFile = this.logicalFileRepository.findFirstByUuid(uuid); + // 检查物理文件是否存在 + if (this.physicalFileRepository.countByUuid(logicalFile.getPhysicalUuid()) == 0) { + // 物理文件不存在 + String message = "view logical file failed, logical file uuid = " + uuid; + message += ", find physical file by uuid failed, physical file uuid = " + logicalFile.getPhysicalUuid(); + logger.error(message); + throw new RuntimeException(message); + } + PhysicalFile physicalFile = this.physicalFileRepository.findFirstByUuid(logicalFile.getPhysicalUuid()); + // 创建协议头 + HttpHeaders headers = new HttpHeaders(); + headers.add("Cache-Control", "no-cache, no-store, must-revalidate"); + // 根据不同浏览器进行处理 + String agent = request.getHeader("User-Agent"); + if (agent.toLowerCase().contains("firefox")) { + headers.add("Content-Disposition", "attachment;fileName==?UTF-8?B?" + + Base64.getEncoder().encodeToString(logicalFile.getName().getBytes("utf-8")) + "?="); + } else { + headers.add("Content-Disposition", + "attachment;fileName=" + URLEncoder.encode(logicalFile.getName(), "utf-8")); + } + headers.add("Pragma", "no-cache"); + headers.add("Expires", "0"); + headers.add("charset", "utf-8"); + // 创建输出流 + ByteArrayOutputStream out = new ByteArrayOutputStream(); + // 输出文件 + List physicalTileFileList = this.physicalTileFileRepository + .findByPhysicalUuidOrderByTile(physicalFile.getUuid()); + for (PhysicalTileFile physicalTileFile : physicalTileFileList) { + Files.copy(Paths.get(physicalTileFile.getPath()), out); + } + MediaType contentType = MediaType.APPLICATION_OCTET_STREAM; + if (logicalFile.getType().equalsIgnoreCase("html")) { + contentType = MediaType.TEXT_HTML; + } else if (logicalFile.getType().equalsIgnoreCase("txt")) { + contentType = MediaType.TEXT_PLAIN; + } else if (logicalFile.getType().equalsIgnoreCase("xml")) { + contentType = MediaType.TEXT_XML; + } else if (logicalFile.getType().equalsIgnoreCase("gif")) { + contentType = MediaType.IMAGE_GIF; + } else if (logicalFile.getType().equalsIgnoreCase("jpg")) { + contentType = MediaType.IMAGE_JPEG; + } else if (logicalFile.getType().equalsIgnoreCase("png")) { + contentType = MediaType.IMAGE_PNG; + } else if (logicalFile.getType().equalsIgnoreCase("json")) { + contentType = MediaType.APPLICATION_JSON; + } else if (logicalFile.getType().equalsIgnoreCase("pdf")) { + contentType = MediaType.APPLICATION_PDF; + } + Resource resource = new InputStreamResource(new ByteArrayInputStream(out.toByteArray())); + + return ResponseEntity.ok().headers(headers).contentLength(physicalFile.getLength()).contentType(contentType) + .body(resource); + } + + /** + * 浏览逻辑文件 + * + * @param id + * 逻辑文件编号 + * @return + * @throws IOException + */ + public ResponseEntity view(HttpServletRequest request, Long id) throws IOException { + // 检查参数 + if (id == null) { + String message = "view logical file failed, id is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 查找逻辑文件 + Optional query = this.logicalFileRepository.findById(id); + if (query.isPresent()) { + LogicalFile logicalFile = query.get(); + // 检查物理文件是否存在 + if (this.physicalFileRepository.countByUuid(logicalFile.getPhysicalUuid()) == 0) { + // 物理文件不存在 + String message = "view logical file failed, logical file id = " + id; + message += ", find physical file by uuid failed, physical file uuid = " + logicalFile.getPhysicalUuid(); + logger.error(message); + throw new RuntimeException(message); + } + PhysicalFile physicalFile = this.physicalFileRepository.findFirstByUuid(logicalFile.getPhysicalUuid()); + // 创建协议头 + HttpHeaders headers = new HttpHeaders(); + headers.add("Cache-Control", "no-cache, no-store, must-revalidate"); + // 根据不同浏览器进行处理 + String agent = request.getHeader("User-Agent"); + if (agent.toLowerCase().contains("firefox")) { + headers.add("Content-Disposition", "attachment;fileName==?UTF-8?B?" + + Base64.getEncoder().encodeToString(logicalFile.getName().getBytes("utf-8")) + "?="); + } else { + headers.add("Content-Disposition", + "attachment;fileName=" + URLEncoder.encode(logicalFile.getName(), "utf-8")); + } + headers.add("Pragma", "no-cache"); + headers.add("Expires", "0"); + headers.add("charset", "utf-8"); + // 创建输出流 + ByteArrayOutputStream out = new ByteArrayOutputStream(); + // 输出文件 + List physicalTileFileList = this.physicalTileFileRepository + .findByPhysicalUuidOrderByTile(physicalFile.getUuid()); + for (PhysicalTileFile physicalTileFile : physicalTileFileList) { + Files.copy(Paths.get(physicalTileFile.getPath()), out); + } + MediaType contentType = MediaType.APPLICATION_OCTET_STREAM; + if (logicalFile.getType().equalsIgnoreCase("html")) { + contentType = MediaType.TEXT_HTML; + } else if (logicalFile.getType().equalsIgnoreCase("txt")) { + contentType = MediaType.TEXT_PLAIN; + } else if (logicalFile.getType().equalsIgnoreCase("xml")) { + contentType = MediaType.TEXT_XML; + } else if (logicalFile.getType().equalsIgnoreCase("gif")) { + contentType = MediaType.IMAGE_GIF; + } else if (logicalFile.getType().equalsIgnoreCase("jpg")) { + contentType = MediaType.IMAGE_JPEG; + } else if (logicalFile.getType().equalsIgnoreCase("png")) { + contentType = MediaType.IMAGE_PNG; + } else if (logicalFile.getType().equalsIgnoreCase("json")) { + contentType = MediaType.APPLICATION_JSON; + } else if (logicalFile.getType().equalsIgnoreCase("pdf")) { + contentType = MediaType.APPLICATION_PDF; + } + Resource resource = new InputStreamResource(new ByteArrayInputStream(out.toByteArray())); + + return ResponseEntity.ok().headers(headers).contentLength(physicalFile.getLength()).contentType(contentType) + .body(resource); + } else { + // 逻辑文件不存在 + String message = "view logical file failed, logical file does not exist, id = " + id; + logger.error(message); + throw new RuntimeException(message); + } + } + + /** + * 文件开放 + * + * @param id + * 文件编号 + * @return 文件开放响应 + */ + public void setOpenById(Long id) { + // 检查参数 + if (id == null) { + String message = "set file open failed, id is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 查找逻辑文件 + Optional query = this.logicalFileRepository.findById(id); + if (query.isPresent()) { + // 逻辑文件存在 + LogicalFile file = query.get(); + file.setOpen(true); + // 修改时间 + file.setModifiedTime(new Date()); + this.logicalFileRepository.save(file); + String message = "set logical file open sucess, logical file name = " + file.getName(); + logger.info(message); + } else { + String message = "set logical file open failed, logical file does not exist, id = " + id; + throw new RuntimeException(message); + } + } + + /** + * 关闭文件不让公开访问 + * + * @param id + * 文件编号 + * @return 关闭文件响应 + */ + public void setCloseById(Long id) { + // 检查参数 + if (id == null) { + String message = "set file close failed, id is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 查找逻辑文件 + Optional query = this.logicalFileRepository.findById(id); + if (query.isPresent()) { + // 逻辑文件存在 + LogicalFile file = query.get(); + file.setOpen(false); + // 修改时间 + file.setModifiedTime(new Date()); + this.logicalFileRepository.save(file); + String message = "set logical file close sucess, logical file name = " + file.getName(); + logger.info(message); + } else { + String message = "set logical file close failed, logical file does not exist, id = " + id; + throw new RuntimeException(message); + } + } + + /** + * 文件开放 + * + * @param uuid + * 文件编号 + * @return 文件开放响应 + */ + public void setOpenByUuid(String uuid) { + // 检查参数 + if (StringUtils.isBlank(uuid)) { + String message = "set logical file open failed, uuid is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 查找逻辑文件 + LogicalFile file = this.logicalFileRepository.findFirstByUuid(uuid); + if (file != null) { + // 逻辑文件存在 + file.setOpen(true); + // 修改时间 + file.setModifiedTime(new Date()); + this.logicalFileRepository.save(file); + String message = "set logical file open sucess, logical file name = " + file.getName(); + logger.info(message); + } else { + String message = "set logical file open failed, logical file does not exist, uuid = " + uuid; + throw new RuntimeException(message); + } + } + + /** + * 关闭文件不让公开访问 + * + * @param uuid + * 文件编号 + * @return 关闭文件响应 + */ + public void setCloseByUuid(String uuid) { + // 检查参数 + if (StringUtils.isBlank(uuid)) { + String message = "set logical file close failed, uuid is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 查找逻辑文件 + LogicalFile file = this.logicalFileRepository.findFirstByUuid(uuid); + if (file != null) { + // 逻辑文件存在 + file.setOpen(false); + // 修改时间 + file.setModifiedTime(new Date()); + this.logicalFileRepository.save(file); + String message = "set logical file close sucess, logical file name = " + file.getName(); + logger.info(message); + } else { + String message = "set logical file close failed, logical file does not exist, uuid = " + uuid; + throw new RuntimeException(message); + } + } + + /** + * 文件批量下载 + * + * @param name + * 下载包名称 + * @param uuids + * uuid列表 + * @return 文件压缩包 + */ + public ResponseEntity pldownload(HttpServletRequest request, String name, List uuids) { + // 检查参数 + if (StringUtils.isBlank(name)) { + String message = "download logical files in package failed, name is null, please set a name for download package."; + logger.error(message); + throw new RuntimeException(message); + } + if (uuids.isEmpty()) { + String message = "download logical files in package failed, uuids is null."; + logger.error(message); + throw new RuntimeException(message); + } + try { + // 创建临时文件夹 + String downloadTempDirectoryPath = this.location.concat(File.separator) + .concat(UUID.randomUUID().toString()); + File downloadTempDirectory = new File(downloadTempDirectoryPath); + downloadTempDirectory.mkdirs(); + // 下载文件 + for (String uuid : uuids) { + // 检查逻辑文件是否存在 + if (this.logicalFileRepository.countByUuid(uuid) == 0) { + // 逻辑文件不存在 + String message = "download logical file failed, logical file does not exist, uuid = " + uuid; + logger.error(message); + throw new RuntimeException(message); + } + LogicalFile logicalFile = this.logicalFileRepository.findFirstByUuid(uuid); + // 检查物理文件是否存在 + if (this.physicalFileRepository.countByUuid(logicalFile.getPhysicalUuid()) == 0) { + // 物理文件不存在 + String message = "download logical file failed, logical file uuid = " + uuid; + message += ", find physical file by uuid failed, physical file uuid = " + + logicalFile.getPhysicalUuid(); + logger.error(message); + throw new RuntimeException(message); + } + PhysicalFile physicalFile = this.physicalFileRepository.findFirstByUuid(logicalFile.getPhysicalUuid()); + // 获取文件名称 + String filename = logicalFile.getName(); + FileOutputStream out = new FileOutputStream(downloadTempDirectoryPath + File.separator + filename); + // 输出文件 + List physicalTileFileList = this.physicalTileFileRepository + .findByPhysicalUuidOrderByTile(physicalFile.getUuid()); + for (PhysicalTileFile physicalTileFile : physicalTileFileList) { + Files.copy(Paths.get(physicalTileFile.getPath()), out); + } + } + // 压缩文件夹 + Project project = new Project(); + Zip zip = new Zip(); + zip.setProject(project); + File zipFile = new File(downloadTempDirectoryPath.concat(".zip")); + zip.setDestFile(zipFile); + FileSet fileSet = new FileSet(); + fileSet.setProject(project); + fileSet.setDir(downloadTempDirectory); + zip.addFileset(fileSet); + zip.execute(); + // 删除临时文件夹及压缩文件 + FileUtils.deleteDirectory(downloadTempDirectory); + // 创建协议头 + HttpHeaders headers = new HttpHeaders(); + headers.add("Content-Type", "application/octet-stream"); + headers.add("Cache-Control", "no-cache, no-store, must-revalidate"); + // 根据不同浏览器进行处理 + String agent = request.getHeader("User-Agent"); + if (agent.toLowerCase().contains("firefox")) { + headers.add("Content-Disposition", "attachment;fileName==?UTF-8?B?" + + Base64.getEncoder().encodeToString(name.concat(".zip").getBytes("utf-8")) + "?="); + } else { + headers.add("Content-Disposition", + "attachment;fileName=" + URLEncoder.encode(name.concat(".zip"), "utf-8")); + } + headers.add("Pragma", "no-cache"); + headers.add("Expires", "0"); + headers.add("charset", "utf-8"); + // 创建输出流 + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Files.copy(zipFile.toPath(), out); + // 删除压缩文件 + // zipFile.delete(); + Resource resource = new InputStreamResource(new ByteArrayInputStream(out.toByteArray())); + + return ResponseEntity.ok().headers(headers).contentLength(zipFile.length()) + .contentType(MediaType.APPLICATION_OCTET_STREAM).body(resource); + } catch (FileNotFoundException e) { + String message = "download logical file failed, name = " + name; + message += ", uuids = " + uuids.toString(); + logger.error(message, e); + throw new RuntimeException(message); + } catch (IOException e) { + String message = "download logical file failed, name = " + name; + message += ", uuids = " + uuids.toString(); + logger.error(message, e); + throw new RuntimeException(message); + } + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/LogicalFileService.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/LogicalFileService.java new file mode 100644 index 0000000..a7be38b --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/LogicalFileService.java @@ -0,0 +1,5 @@ +package com.sinoparasoft.storage.service; + +public class LogicalFileService { + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/MetadataService.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/MetadataService.java new file mode 100644 index 0000000..3b985de --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/MetadataService.java @@ -0,0 +1,71 @@ +package com.sinoparasoft.storage.service; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.sinoparasoft.storage.model.Metadata; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +/** + * 元数据管理服务类 + * + * @author 袁涛 + * @date 2017.10.27 + */ +@Component +public class MetadataService { + private static final Logger logger = LoggerFactory.getLogger(MetadataService.class); + + /** + * 将JSON字符串转换为元数据类型 + * + * @param json + * JSON字符串 + * @return 元数据类型 + */ + public Metadata toMetadata(String json) { + Metadata retValue = null; + + ObjectMapper mapper = new ObjectMapper(); + try { + retValue = mapper.readValue(json, Metadata.class); + } catch (JsonParseException e) { + String msg = "json string parse failed, json = " + json; + logger.error(msg, e); + } catch (JsonMappingException e) { + String msg = "json string transform to metadata failed, json = " + json; + logger.error(msg, e); + } catch (IOException e) { + String msg = "json string transform to metadata failed, json = " + json; + logger.error(msg, e); + } + + return retValue; + } + + /** + * 将元数据类型转换为JSON字符串 + * + * @param metadata + * 元数据类型 + * @return JSON字符串 + */ + public String toJson(Metadata metadata) { + String retValue = "{}"; + + ObjectMapper mapper = new ObjectMapper(); + try { + retValue = mapper.writeValueAsString(metadata); + } catch (JsonProcessingException e) { + String msg = "metadata transform to json string failed, metadata = " + metadata.toString(); + logger.error(msg, e); + } + + return retValue; + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/PhysicalFileService.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/PhysicalFileService.java new file mode 100644 index 0000000..a322f2e --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/PhysicalFileService.java @@ -0,0 +1,214 @@ +package com.sinoparasoft.storage.service; + +import com.sinoparasoft.storage.domain.LogicalFile; +import com.sinoparasoft.storage.domain.PhysicalFile; +import com.sinoparasoft.storage.domain.PhysicalTileFile; +import com.sinoparasoft.storage.model.Metadata; +import com.sinoparasoft.storage.repository.LogicalFileRepository; +import com.sinoparasoft.storage.repository.PhysicalFileRepository; +import com.sinoparasoft.storage.repository.PhysicalTileFileRepository; +import com.sinoparasoft.storage.utils.DigestUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 物理文件管理服务类 + * + * @author 袁涛 + * @date 2018.09.14 + */ +@Component +public class PhysicalFileService { + private static final Logger logger = LoggerFactory.getLogger(PhysicalFileService.class); + + /** + * 物理文件管理接口 + */ + @Autowired + private PhysicalFileRepository physicalFileRepository; + + /** + * 物理分块文件管理接口 + */ + @Autowired + private PhysicalTileFileRepository physicalTileFileRepository; + + @Autowired + private PhysicalTileFileService physicalTileFileService; + + /** + * 逻辑文件管理接口 + */ + @Autowired + private LogicalFileRepository logicalFileRepository; + + /** + * 元数据管理服务类 + */ + @Autowired + private MetadataService metadataService; + + /** + * 新建物理文件 + * + * @param logicalUuid + * 逻辑文件编号 + * @param tile + * 文件块号,从0开始 + * @param tiles + * 文件块数 + * @param file + * 文件内容 + */ + public void create(String logicalUuid, Integer tile, Integer tiles, MultipartFile file) { + // 检查参数 + if (StringUtils.isBlank(logicalUuid)) { + String message = "logical uuid is null."; + logger.error(message); + throw new RuntimeException(message); + } + if(tile == null || tile < 0) { + String message = "tile is null or less than 0."; + logger.error(message); + throw new RuntimeException(message); + } + if(tiles == null || tiles < 0) { + String message = "tiles is null or less than 0."; + logger.error(message); + throw new RuntimeException(message); + } + if(file == null) { + String message = "file is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 检查逻辑文件是否存在 + if (this.logicalFileRepository.countByUuid(logicalUuid) == 0) { + String message = "find logical file by uuid failed, uuid = " + logicalUuid; + logger.error(message); + + throw new RuntimeException(message); + } + LogicalFile logicalFile = this.logicalFileRepository.findFirstByUuid(logicalUuid); + + PhysicalFile physicalFile = null; + if (this.physicalFileRepository.countByUuid(logicalFile.getPhysicalUuid()) > 0) { + physicalFile = this.physicalFileRepository.findFirstByUuid(logicalFile.getPhysicalUuid()); + } else { + physicalFile = new PhysicalFile(); + physicalFile.setUuid(logicalFile.getPhysicalUuid()); + // 物理文件块数 + physicalFile.setTiles(tiles); + // 创建时间 + physicalFile.setCreateTime(new Date()); + // 修改时间 + physicalFile.setModifiedTime(new Date()); + // 校验文件是否健康 + physicalFile.setHealthy(false); + // 校验时间 + physicalFile.setCheckTime(new Date()); + // 保存物理文件信息 + this.physicalFileRepository.save(physicalFile); + } + // 存储物理分块文件 + this.physicalTileFileService.create(physicalFile.getUuid(), tile, file); + if (this.physicalTileFileRepository.countByPhysicalUuid(physicalFile.getUuid()).intValue() == tiles) { + // 物理分块文件存储完毕 + List physicalTileFileList = this.physicalTileFileRepository + .findByPhysicalUuidOrderByTile(physicalFile.getUuid()); + List filePathList = new ArrayList(); + Long length = 0L; + for (PhysicalTileFile physicalTileFile : physicalTileFileList) { + filePathList.add(physicalTileFile.getPath()); + length += physicalTileFile.getLength(); + } + // 文件MD5 + String md5 = DigestUtils.calculate(filePathList, DigestUtils.MD5); + physicalFile.setMd5(md5); + // 文件SHA + String sha = DigestUtils.calculate(filePathList, DigestUtils.SHA); + physicalFile.setSha(sha); + // 查询物理文件是否存在 + if (this.physicalFileRepository.countByMd5AndSha(md5, sha) > 0) { + // 物理文件已经存在 + PhysicalFile srcPhysicalFile = this.physicalFileRepository.findFirstByMd5AndSha(md5, sha); + // 删除物理文件记录 + this.delete(physicalFile.getUuid()); + + // 保存逻辑文件信息 + logicalFile.setPhysicalUuid(srcPhysicalFile.getUuid()); + // 文件长度 + logicalFile.setLength(srcPhysicalFile.getLength()); + // 元数据,JSON格式 + Metadata metadata = new Metadata(); + metadata.setName(logicalFile.getName()); + metadata.setLength(logicalFile.getLength()); + metadata.setModifiedTime(logicalFile.getModifiedTime()); + metadata.setCreateTime(logicalFile.getCreateTime()); + metadata.setTag(logicalFile.getTag()); + logicalFile.setMetadata(this.metadataService.toJson(metadata)); + this.logicalFileRepository.save(logicalFile); + + } else { + // 物理文件不存在 + // 修改时间 + physicalFile.setModifiedTime(new Date()); + // 文件长度 + physicalFile.setLength(length); + // 校验文件是否健康 + physicalFile.setHealthy(true); + // 校验时间 + physicalFile.setCheckTime(new Date()); + // 保存物理文件信息 + this.physicalFileRepository.save(physicalFile); + + // 保存逻辑文件信息 + logicalFile.setLength(length); + // 元数据,JSON格式 + Metadata metadata = new Metadata(); + metadata.setName(logicalFile.getName()); + metadata.setLength(logicalFile.getLength()); + metadata.setModifiedTime(logicalFile.getModifiedTime()); + metadata.setCreateTime(logicalFile.getCreateTime()); + metadata.setTag(logicalFile.getTag()); + logicalFile.setMetadata(this.metadataService.toJson(metadata)); + this.logicalFileRepository.save(logicalFile); + } + } + } + + /** + * 删除物理文件 + * + * @param uuid + * 物理文件编号 + * @return 是否成功 + */ + public Boolean delete(String uuid) { + Boolean retValue = false; + + if (this.physicalFileRepository.countByUuid(uuid) > 0) { + PhysicalFile physicalFile = this.physicalFileRepository.findFirstByUuid(uuid); + if (this.physicalTileFileRepository.countByPhysicalUuid(physicalFile.getUuid()) > 0) { + // 删除物理分块文件记录 + List physicalTileFileList = this.physicalTileFileRepository + .findByPhysicalUuidOrderByTile(physicalFile.getUuid()); + this.physicalTileFileRepository.deleteAll(physicalTileFileList); + } + // 删除物理文件记录 + this.physicalFileRepository.delete(physicalFile); + retValue = true; + } + + return retValue; + } + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/PhysicalTileFileService.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/PhysicalTileFileService.java new file mode 100644 index 0000000..cbe4dc1 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/PhysicalTileFileService.java @@ -0,0 +1,218 @@ +package com.sinoparasoft.storage.service; + +import com.sinoparasoft.storage.domain.PhysicalTileFile; +import com.sinoparasoft.storage.domain.StorageRegion; +import com.sinoparasoft.storage.repository.PhysicalTileFileRepository; +import com.sinoparasoft.storage.repository.StorageRegionRepository; +import com.sinoparasoft.storage.utils.DigestUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +/** + * 物理分块文件管理服务类 + * + * @author 袁涛 + * @date 2018.09.14 + */ +@Component +public class PhysicalTileFileService { + private static final Logger logger = LoggerFactory.getLogger(PhysicalTileFileService.class); + + /** + * 物理分块文件管理接口 + */ + @Autowired + private PhysicalTileFileRepository physicalTileFileRepository; + + /** + * 存储区管理接口 + */ + @Autowired + private StorageRegionRepository storageRegionRepository; + + /** + * 存储区管理服务 + */ + @Autowired + private StorageRegionService storageRegionService; + + /** + * 新建物理分块文件 + * + * @param physicalUuid + * 物理文件编号 + * @param tile + * 物理分块文件序号 + * @param file + * 物理分块文件内容 + */ + public void create(String physicalUuid, Integer tile, MultipartFile file) { + // 检查参数 + if (StringUtils.isBlank(physicalUuid)) { + String message = "physical file uuid is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 获取可用存储区 + StorageRegion region = this.storageRegionService.getAvailableStorageRegion(file.getSize()); + if (region == null) { + String message = "find available storage region failed, file size = " + file.getSize(); + logger.error(message); + + throw new RuntimeException(message); + } + + // 创建文件存储目录 + Calendar calendar = Calendar.getInstance(); + Integer year = calendar.get(Calendar.YEAR); + Integer month = calendar.get(Calendar.MONTH); + Integer day = calendar.get(Calendar.DAY_OF_MONTH); + Path directoryPath = Paths.get(region.getPath(), year.toString(), month.toString(), day.toString()); + File directory = directoryPath.toFile(); + if (directory.exists() || directory.mkdirs()) { + // 文件编号 + String uuid = UUID.randomUUID().toString(); + File destFile = new File(directory.getAbsolutePath(), uuid); + try { + file.transferTo(destFile); + // 文件MD5 + String md5 = DigestUtils.calculate(destFile.getAbsolutePath(), DigestUtils.MD5); + // 文件SHA + String sha = DigestUtils.calculate(destFile.getAbsolutePath(), DigestUtils.SHA); + if (this.physicalTileFileRepository.countByMd5AndSha(md5, sha) == 0) { + // 物理分块文件不存在 + PhysicalTileFile physicalTileFile = new PhysicalTileFile(); + // 文件编号 + physicalTileFile.setUuid(uuid); + // 物理文件编号 + physicalTileFile.setPhysicalUuid(physicalUuid); + // 物理分块文件序号 + physicalTileFile.setTile(tile); + // 文件路径 + physicalTileFile.setPath(destFile.getAbsolutePath()); + // 文件MD5 + physicalTileFile.setMd5(md5); + // 文件SHA + physicalTileFile.setSha(sha); + // 创建时间 + physicalTileFile.setCreateTime(new Date()); + // 修改时间 + physicalTileFile.setModifiedTime(new Date()); + // 文件大小 + physicalTileFile.setLength(file.getSize()); + // 存储区编号 + physicalTileFile.setStorageRegionUuid(region.getUuid()); + // 文件是否健康 + physicalTileFile.setHealthy(true); + // 校验时间 + physicalTileFile.setCheckTime(new Date()); + this.physicalTileFileRepository.save(physicalTileFile); + } else { + // 物理分块文件存在 + // 删除临时文件 + destFile.delete(); + // 复制物理分块文件信息 + PhysicalTileFile srcPhysicalTileFile = this.physicalTileFileRepository.findFirstByMd5AndSha(md5, + sha); + PhysicalTileFile destPhysicalTileFile = new PhysicalTileFile(); + // 文件编号 + destPhysicalTileFile.setUuid(uuid); + // 物理文件编号 + destPhysicalTileFile.setPhysicalUuid(physicalUuid); + // 物理分块文件序号 + destPhysicalTileFile.setTile(tile); + // 文件路径 + destPhysicalTileFile.setPath(srcPhysicalTileFile.getPath()); + // 文件MD5 + destPhysicalTileFile.setMd5(srcPhysicalTileFile.getMd5()); + // 文件SHA + destPhysicalTileFile.setSha(srcPhysicalTileFile.getSha()); + // 创建时间 + destPhysicalTileFile.setCreateTime(new Date()); + // 修改时间 + destPhysicalTileFile.setModifiedTime(new Date()); + // 文件大小 + destPhysicalTileFile.setLength(srcPhysicalTileFile.getLength()); + // 存储区编号 + destPhysicalTileFile.setStorageRegionUuid(srcPhysicalTileFile.getStorageRegionUuid()); + // 文件是否健康 + destPhysicalTileFile.setHealthy(srcPhysicalTileFile.getHealthy()); + // 校验时间 + destPhysicalTileFile.setCheckTime(srcPhysicalTileFile.getCheckTime()); + this.physicalTileFileRepository.save(destPhysicalTileFile); + } + } catch (IllegalStateException e) { + String message = "store file failed, path = " + destFile.getAbsolutePath(); + logger.error(message); + + throw new RuntimeException(message); + } catch (IOException e) { + String message = "store file failed, path = " + destFile.getAbsolutePath(); + logger.error(message); + + throw new RuntimeException(message); + } + } else { + // 文件存储目录不存在且目录创建失败 + region.setHealthy(false); + region.setCheckTime(calendar.getTime()); + this.storageRegionRepository.save(region); + + String message = "directory not exits and create directory failed, directory = " + + directory.getAbsolutePath(); + logger.error(message); + throw new RuntimeException(message); + } + } + + /** + * 定期检查物理文件的状态,每隔一小时检查一次 + */ + @Scheduled(cron = "0 0 0/1 * * ? ") + public void check() { + Long start = System.currentTimeMillis(); + if (this.physicalTileFileRepository.count() > 0) { + List files = this.physicalTileFileRepository.findAll(); + for (PhysicalTileFile file : files) { + // 判断文件是否存在 + if (new File(file.getPath()).exists()) { + // 文件MD5 + String md5 = DigestUtils.calculate(file.getPath(), DigestUtils.MD5); + // 文件SHA + String sha = DigestUtils.calculate(file.getPath(), DigestUtils.SHA); + if (md5.equals(file.getMd5()) && sha.equals(file.getSha())) { + // 文件是否健康 + file.setHealthy(true); + } else { + // 文件是否健康 + file.setHealthy(false); + } + } else { + // 文件是否健康 + file.setHealthy(false); + } + + // 校验时间 + file.setCheckTime(new Date()); + this.physicalTileFileRepository.save(file); + } + } + Long end = System.currentTimeMillis(); + String msg = "check physical tile file use " + (end - start) + " ms."; + logger.info(msg); + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/StorageRegionService.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/StorageRegionService.java new file mode 100644 index 0000000..36c6ec9 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/service/StorageRegionService.java @@ -0,0 +1,420 @@ +package com.sinoparasoft.storage.service; + +import com.sinoparasoft.storage.domain.StorageRegion; +import com.sinoparasoft.storage.model.StorageRegionQueryRequest; +import com.sinoparasoft.storage.repository.PhysicalTileFileRepository; +import com.sinoparasoft.storage.repository.StorageRegionRepository; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +/** + * 物理存储区管理服务类 + * + * @author 袁涛 + * @date 2017.10.27 + */ +@Component +public class StorageRegionService { + private static final Logger logger = LoggerFactory.getLogger(StorageRegionService.class); + + /** + * 存储区管理接口 + */ + @Autowired + private StorageRegionRepository storageRegionRepository; + + /** + * 物理分块文件管理接口 + */ + @Autowired + private PhysicalTileFileRepository physicalTileFileRepository; + + /** + * 获取物理存储区列表 + * + * @param request + * 物理存储区查询请求 + * @param pageable + * 分页信息 + * @return 物理存储区列表 + */ + public Page findAll(StorageRegionQueryRequest request, Pageable pageable) { + if (StringUtils.isBlank(request.getName())) { + // 物理存储区名称为空 + return this.storageRegionRepository.findAll(pageable); + } else { + // 物理存储区名称不为空 + String name = request.getName(); + if (!name.startsWith("%")) { + name = "%" + name; + } + if (!name.endsWith("%")) { + name = name + "%"; + } + return this.storageRegionRepository.findByNameLike(name, pageable); + } + } + + /** + * 根据物理存储区编号查询物理存储区信息 + * + * @param id + * 物理存储区编号 + * @return 物理存储区信息 + */ + public StorageRegion findById(Long id) { + StorageRegion retValue = null; + if (id == null) { + String message = "storage region id is null."; + logger.error(message); + throw new RuntimeException(message); + } + Optional query = this.storageRegionRepository.findById(id); + if (query.isPresent()) { + retValue = query.get(); + } else { + String message = "find storage region by id failed, id = " + id; + logger.error(message); + throw new RuntimeException(message); + } + return retValue; + } + + /** + * 新建物理存储区 + * + * @param request + * 物理存储区信息 + * @return 物理存储区信息 + */ + public StorageRegion create(StorageRegion request) { + // 检查参数 + if (StringUtils.isBlank(request.getName())) { + String message = "storage region name is null."; + logger.error(message); + throw new RuntimeException(message); + } + if (StringUtils.isBlank(request.getPath())) { + String message = "storage region path is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 检查存储区是否存在 + if (this.storageRegionRepository.countByName(request.getName()) > 0) { + String message = "create storage region failed, name already exists, name = " + request.getName(); + logger.error(message); + throw new RuntimeException(message); + } + // 写入数据库 + StorageRegion region = new StorageRegion(); + // 存储区编号 + String uuid = UUID.randomUUID().toString(); + region.setUuid(uuid); + // 存储区名称 + region.setName(request.getName()); + // 存储区描述 + region.setDescription(request.getDescription()); + // 存储区路径 + region.setPath(request.getPath()); + // 存储区可用容量,单位:字节 + File file = new File(request.getPath()); + Long availableSize = file.getUsableSpace(); + region.setAvailableSize(availableSize); + // 存储区已用容量,单位:字节 + Long usedSize = this.getDirectorySize(file); + region.setUsedSize(usedSize); + // 存储区总容量,单位:字节 + Long totalSize = availableSize + usedSize; + region.setTotalSize(totalSize); + // 检查存储区是否健康 + Boolean healthy = this.isHealthy(request.getPath()); + region.setHealthy(healthy); + // 创建时间 + region.setCreateTime(new Date()); + // 修改时间 + region.setModifiedTime(new Date()); + // 检查时间 + region.setCheckTime(new Date()); + this.storageRegionRepository.save(region); + + String message = "create storage region sucess, name = " + request.getName(); + logger.info(message); + + return region; + } + + /** + * 删除物理存储区 + * + * @param id + * 物理存储区编号 + */ + public void delete(Long id) { + // 检查参数 + if (id == null) { + String message = "delete storage region failed, id is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 查找物理存储区 + Optional query = this.storageRegionRepository.findById(id); + if (query.isPresent()) { + // 物理存储区存在,在数据库中删除记录 + StorageRegion region = query.get(); + // 查看物理存储区下是否存在文件 + if (this.physicalTileFileRepository.countByStorageRegionUuid(region.getUuid()) > 0) { + // 存储区上有文件,不能删除,删除必须先清空存储区上的文件 + String message = "storage region has files, delete must clear files first, storage region uuid = " + + region.getUuid(); + logger.error(message); + + throw new RuntimeException(message); + } else { + this.storageRegionRepository.delete(region); + String message = "delete storage region sucess, storage region id = " + id; + logger.info(message); + } + } else { + // 物理存储区不存在 + String message = "delete storage region failed, storage region does not exist, id = " + id; + logger.error(message); + throw new RuntimeException(message); + } + } + + /** + * 根据物理存储区UUID编号删除物理存储区 + * + * @param uuid + * 物理存储区UUID编号 + */ + public void delete(String uuid) { + // 检查参数 + if (StringUtils.isBlank(uuid)) { + String message = "delete storage region failed, uuid is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 查找物理存储区 + if (this.storageRegionRepository.countByUuid(uuid) > 0) { + // 查看物理存储区下是否存在文件 + if (this.physicalTileFileRepository.countByStorageRegionUuid(uuid) > 0) { + // 存储区上有文件,不能删除,删除必须先清空存储区上的文件 + String message = "storage region has files, delete must clear files first, storage region uuid = " + + uuid; + logger.error(message); + + throw new RuntimeException(message); + } else { + StorageRegion region = this.storageRegionRepository.findFirstByUuid(uuid); + this.storageRegionRepository.delete(region); + String message = "delete storage region sucess, storage region uuid = " + uuid; + logger.info(message); + } + } else { + // 物理存储区不存在 + String message = "delete storage region failed, storage region does not exist, uuid = " + uuid; + logger.error(message); + throw new RuntimeException(message); + } + } + + /** + * 批量删除物理存储区 + * + * @param uuids + * 物理存储区UUID编号列表 + */ + public void delete(List uuids) { + if (uuids != null && uuids.size() > 0) { + for (String uuid : uuids) { + this.delete(uuid); + } + } + } + + /** + * 更新物理存储区 + * + * @param request + * 物理存储区信息 + */ + public void update(StorageRegion request) { + // 检查参数 + if (request.getId() == null) { + String message = "update storage region failed, id is null."; + logger.error(message); + throw new RuntimeException(message); + } + // 查找物理存储区 + Optional query = this.storageRegionRepository.findById(request.getId()); + if (query.isPresent()) { + // 物理存储区存在 + StorageRegion region = query.get(); + // 字段非空才更新 + if (!StringUtils.isBlank(request.getName())) { + // 查询物理存储区是否重名 + if (this.storageRegionRepository.countByIdNotAndName(request.getId(), request.getName()) > 0) { + String message = "update storage region failed, name already exists, name = " + request.getName(); + logger.error(message); + throw new RuntimeException(message); + } else { + // 物理存储区名称 + region.setName(request.getName()); + } + } + if (!StringUtils.isBlank(request.getDescription())) { + // 物理存储区描述 + region.setDescription(request.getDescription()); + } + // 修改时间 + region.setModifiedTime(new Date()); + this.storageRegionRepository.save(region); + String message = "update storage region information sucess, application name = " + request.getName(); + logger.info(message); + } else { + // 物理存储区不存在 + String message = "update storage region failed, application does not exist, id = " + request.getId(); + logger.error(message); + throw new RuntimeException(message); + } + } + + /** + * 获取可用存储区 + * + * @param availableSize + * 可用空间 + * @return 可用存储区 + */ + public StorageRegion getAvailableStorageRegion(Long availableSize) { + StorageRegion retValue = null; + + if (this.storageRegionRepository.countByAvailableSizeGreaterThanAndHealthy(availableSize, true) > 0) { + List regions = this.storageRegionRepository + .findByAvailableSizeGreaterThanAndHealthy(availableSize, true); + retValue = regions.get(0); + } + + return retValue; + } + + /** + * 获取文件夹大小 + * + * @param directory + * 文件夹 + * @return 文件夹大小 + */ + public Long getDirectorySize(File directory) { + Long retValue = 0L; + + if (directory.isDirectory()) { + File[] files = directory.listFiles(); + for (File file : files) { + retValue += this.getDirectorySize(file); + } + } else { + retValue = directory.length(); + } + + return retValue; + } + + /** + * 判断文件夹是否健康 + * + * @param path + * 文件夹路径 + * @return 是否健康 + */ + public Boolean isHealthy(String path) { + Boolean retValue = false; + + String content = "test"; + String uuid = UUID.randomUUID().toString(); + Path filePath = Paths.get(path, uuid); + File file = filePath.toFile(); + + try { + if (file.exists() || file.createNewFile()) { + // 写入文件内容 + Files.write(filePath, content.getBytes()); + // 读取文件内容 + byte[] data = Files.readAllBytes(filePath); + String text = new String(data); + if (text.equals(content)) { + // 删除文件 + Files.delete(filePath); + retValue = true; + } else { + String msg = "write file content = " + content; + msg += ", not eques to read file content = " + text; + logger.error(msg); + } + } else { + String msg = "create new file failed, path = " + filePath.toString(); + logger.error(msg); + } + + } catch (FileNotFoundException e) { + String msg = "find file failed, file path = " + filePath.toString(); + logger.error(msg, e); + } catch (IOException e) { + String msg = "read or write file failed, file path = " + filePath.toString(); + logger.error(msg, e); + } + + return retValue; + } + + /** + * 定期检查存储区状态,每隔一小时检查一次 + */ + @Scheduled(cron = "30 * * * * ? ") + public void check() { + Long start = System.currentTimeMillis(); + if (this.storageRegionRepository.count() > 0) { + List regions = this.storageRegionRepository.findAll(); + for (StorageRegion region : regions) { + // 存储区可用容量,单位:字节 + File file = new File(region.getPath()); + Long availableSize = file.getUsableSpace(); + region.setAvailableSize(availableSize); + // 存储区已用容量,单位:字节 + Long usedSize = this.getDirectorySize(file); + region.setUsedSize(usedSize); + // 存储区总容量,单位:字节 + Long totalSize = availableSize + usedSize; + region.setTotalSize(totalSize); + // 检查存储区是否健康 + Boolean healthy = this.isHealthy(region.getPath()); + region.setHealthy(healthy); + // 检查时间 + region.setCheckTime(new Date()); + this.storageRegionRepository.save(region); + } + } + Long end = System.currentTimeMillis(); + String msg = "check storage region use " + (end - start) + " ms."; + logger.info(msg); + } + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/CasUtils.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/CasUtils.java new file mode 100644 index 0000000..bc116a2 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/CasUtils.java @@ -0,0 +1,242 @@ +package com.sinoparasoft.storage.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.HttpsURLConnection; +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; +import org.apache.commons.lang3.StringUtils; + +/** + * 统一身份认证工具类 + * + * @author 袁涛 + * @date 2017.10.27 + */ +public class CasUtils { + private static final Logger logger = LoggerFactory.getLogger(CasUtils.class); + + /** + * 统一身份认证服务器访问地址 + */ + private String casServerUrl; + + /** + * 统一身份认证获取令牌地址 + */ + private String accessTokenUrl; + + /** + * 访问目标地址 + */ + private String targetUrl; + + public String getCasServerUrl() { + return casServerUrl; + } + + public void setCasServerUrl(String casServerUrl) { + this.casServerUrl = casServerUrl; + } + + public String getAccessTokenUrl() { + return accessTokenUrl; + } + + public void setAccessTokenUrl(String accessTokenUrl) { + this.accessTokenUrl = accessTokenUrl; + } + + public String getTargetUrl() { + return targetUrl; + } + + public void setTargetUrl(String targetUrl) { + this.targetUrl = targetUrl; + } + + /** + * 获取TGT票据 + * + * @param username + * 用户名 + * @param password + * 密码 + * @return TGT票据 + */ + public String getTicketGrantingTicket(String username, String password) { + String retValue = null; + + // 检查参数 + if (StringUtils.isBlank(this.accessTokenUrl)) { + String message = "access token url is blank."; + logger.error(message); + throw new RuntimeException(message); + } + if (StringUtils.isBlank(username)) { + String message = "username is blank."; + logger.error(message); + throw new RuntimeException(message); + } + if (StringUtils.isBlank(password)) { + String message = "password is blank."; + logger.error(message); + throw new RuntimeException(message); + } + HttpsURLConnection httpsURLConnection = null; + try { + httpsURLConnection = (HttpsURLConnection) this.openConnection(this.accessTokenUrl, "POST"); + // 参数 + String parameters = "username=" + URLEncoder.encode(username, "UTF-8"); + parameters += "&password" + "=" + URLEncoder.encode(password, "UTF-8"); + parameters += "&service" + "=" + URLEncoder.encode(this.targetUrl, "UTF-8"); + + OutputStreamWriter out = new OutputStreamWriter(httpsURLConnection.getOutputStream()); + BufferedWriter writer = new BufferedWriter(out); + // 添加参数到目标服务器 + writer.write(parameters); + writer.flush(); + writer.close(); + out.close(); + + // 获取token + String tgt = httpsURLConnection.getHeaderField("location"); + // 获取返回值 + if (tgt != null && httpsURLConnection.getResponseCode() == 201) { + tgt = tgt.substring(tgt.lastIndexOf("/") + 1); + } + retValue = tgt; + } catch (IOException e) { + String message = "get ticket granting ticket failed, username = " + username + ", password = " + password; + logger.error(message, e); + } finally { + try { + if (httpsURLConnection != null) { + httpsURLConnection.disconnect(); + } + } catch (Exception e) { + String message = "disconnect https url connection failed, username = " + username + ", password = " + + password; + logger.error(message, e); + } + } + + return retValue; + } + + /** + * 打开URL连接 + * + * @param url + * 访问地址 + * @param method + * 访问方法 + * @return URL连接 + * @throws IOException + */ + public URLConnection openConnection(String url, String method) throws IOException { + // 检查参数 + if (StringUtils.isBlank(url)) { + String message = "url is blank."; + logger.error(message); + throw new RuntimeException(message); + } + if (StringUtils.isBlank(method)) { + String message = "method is blank."; + logger.error(message); + throw new RuntimeException(message); + } + URL uRL = new URL(url); + HttpsURLConnection httpsURLConnection = (HttpsURLConnection) uRL.openConnection(); + httpsURLConnection.setDoInput(true); + httpsURLConnection.setDoOutput(true); + httpsURLConnection.setRequestMethod(method); + + return httpsURLConnection; + } + + /** + * 根据TGT获取ST票据 + * + * @param ticketGrantingTicket + * TGT票据 + * @return ST票据 + */ + public String getServiceTicket(String ticketGrantingTicket) { + String retValue = null; + + // 检查参数 + if (StringUtils.isBlank(this.accessTokenUrl)) { + String message = "access token url is blank."; + logger.error(message); + throw new RuntimeException(message); + } + if (StringUtils.isBlank(ticketGrantingTicket)) { + String message = "ticket granting ticket is blank."; + logger.error(message); + throw new RuntimeException(message); + } + + HttpsURLConnection httpsURLConnection = null; + try { + httpsURLConnection = (HttpsURLConnection) this + .openConnection(this.accessTokenUrl + "/" + ticketGrantingTicket, "POST"); + + // 需要访问的目标网站 + String parameters = "service=" + URLEncoder.encode(this.targetUrl, "UTF-8"); + OutputStreamWriter out = new OutputStreamWriter(httpsURLConnection.getOutputStream()); + BufferedWriter writer = new BufferedWriter(out); + // 添加参数到目标服务器 + writer.write(parameters); + writer.flush(); + writer.close(); + out.close(); + + // 获取返回的ticket票据 + BufferedReader in = new BufferedReader(new InputStreamReader(httpsURLConnection.getInputStream())); + retValue = in.readLine(); + } catch (IOException e) { + String message = "get ticket granting ticket failed, ticketGrantingTicket = " + ticketGrantingTicket; + logger.error(message, e); + } finally { + try { + if (httpsURLConnection != null) { + httpsURLConnection.disconnect(); + } + } catch (Exception e) { + String message = "disconnect https url connection failed, ticketGrantingTicket = " + + ticketGrantingTicket; + logger.error(message, e); + } + } + + return retValue; + } + + /** + * 根据用户名和密码获取ST票据 + * + * @param username + * 用户名 + * @param password + * 密码 + * @return ST票据 + */ + public String getServiceTicket(String username, String password) { + String retValue = null; + + // 获取TGT票据 + String ticketGrantingTicket = this.getTicketGrantingTicket(username, password); + if (StringUtils.isBlank(ticketGrantingTicket)) { + String message = "get ticket granting ticket failed, username = " + username + ", password = " + password; + logger.error(message); + throw new RuntimeException(message); + } + retValue = this.getServiceTicket(ticketGrantingTicket); + + return retValue; + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/DigestUtils.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/DigestUtils.java new file mode 100644 index 0000000..1c96d0d --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/DigestUtils.java @@ -0,0 +1,127 @@ +package com.sinoparasoft.storage.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.List; + +/** + * 文件摘要计算工具类 + * + * @author 袁涛 + * @date 2017.10.27 + */ +public class DigestUtils { + private static final Logger logger = LoggerFactory.getLogger(DigestUtils.class); + + /** + * MD5算法 + */ + public static final String MD5 = "MD5"; + + /** + * SHA算法 + */ + public static final String SHA = "SHA"; + + /** + * 文件摘要计算缓冲区大小 + */ + private static final int BUFFER_SISE = 8192; + + /** + * 文件摘要计算 + * + * @param filePath + * 文件路径 + * @param algorithm + * 算法 + * @return 摘要 + */ + public static String calculate(String filePath, String algorithm) { + String retValue = ""; + + try { + MessageDigest digest = MessageDigest.getInstance(algorithm); + byte[] buffer = new byte[DigestUtils.BUFFER_SISE]; + File file = new File(filePath); + FileInputStream in = new FileInputStream(file); + int length = -1; + while ((length = in.read(buffer)) != -1) { + digest.update(buffer, 0, length); + } + in.close(); + retValue = StringUtils.bytesToString(digest.digest()); + } catch (NoSuchAlgorithmException e) { + String msg = "calculate file digest failed, no digest algorithm, algorithm = " + algorithm; + logger.error(msg); + + return retValue; + } catch (FileNotFoundException e) { + String msg = "calculate file digest failed, file not found, file path = " + filePath; + logger.error(msg); + + return retValue; + } catch (IOException e) { + String msg = "calculate file digest failed, file read failed, file path = " + filePath; + logger.error(msg); + + return retValue; + } + + return retValue; + } + + /** + * 文件列表摘要计算 + * + * @param filePathList + * 文件路径列表 + * @param algorithm + * 算法 + * @return 摘要 + */ + public static String calculate(List filePathList, String algorithm) { + String retValue = ""; + + try { + MessageDigest digest = MessageDigest.getInstance(algorithm); + byte[] buffer = new byte[DigestUtils.BUFFER_SISE]; + for (String filePath : filePathList) { + File file = new File(filePath); + FileInputStream in = new FileInputStream(file); + int length = -1; + while ((length = in.read(buffer)) != -1) { + digest.update(buffer, 0, length); + } + in.close(); + } + + retValue = StringUtils.bytesToString(digest.digest()); + } catch (NoSuchAlgorithmException e) { + String msg = "calculate file digest failed, no digest algorithm, algorithm = " + algorithm; + logger.error(msg); + + return retValue; + } catch (FileNotFoundException e) { + String msg = "calculate file digest failed, file not found, file path list = " + filePathList.toString(); + logger.error(msg); + + return retValue; + } catch (IOException e) { + String msg = "calculate file digest failed, file read failed, file path list = " + filePathList.toString(); + logger.error(msg); + + return retValue; + } + + return retValue; + } + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/HttpClientUtils.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/HttpClientUtils.java new file mode 100644 index 0000000..6a98b2d --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/HttpClientUtils.java @@ -0,0 +1,294 @@ +package com.sinoparasoft.storage.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Properties; +import org.apache.commons.lang3.StringUtils; + +/** + * HTTP客户端工具类 + * + * @author 袁涛 + * @date 2018.08.31 + */ +public class HttpClientUtils { + private static final Logger logger = LoggerFactory.getLogger(HttpClientUtils.class); + + /** + * 发送HTTP GET请求 + * + * @param urlPath + * 访问URL地址 + * @param properties + * 请求参数 + * @return HTTP响应 + */ + public static String doGet(String urlPath, Properties properties) { + return HttpClientUtils.doRequest(urlPath, properties, "GET"); + } + + /** + * 发送HTTP GET请求 + * + * @param urlPath + * 请求地址 + * @return 请求响应 + */ + public static String doGet(String urlPath) { + return HttpClientUtils.doRequest(urlPath, "GET"); + } + + /** + * 发送HTTP POST请求 + * + * @param urlPath + * 访问URL地址 + * @param properties + * 请求参数 + * @return HTTP响应 + */ + public static String doPost(String urlPath, Properties properties) { + return HttpClientUtils.doRequest(urlPath, properties, "POST"); + } + + /** + * 发送HTTP POST请求 + * + * @param urlPath + * 请求地址 + * @return 请求响应 + */ + public static String doPost(String urlPath) { + return HttpClientUtils.doRequest(urlPath, "POST"); + } + + /** + * 发送HTTP PUT请求 + * + * @param urlPath + * 访问URL地址 + * @param properties + * 请求参数 + * @return HTTP响应 + */ + public static String doPut(String urlPath, Properties properties) { + return HttpClientUtils.doRequest(urlPath, properties, "PUT"); + } + + /** + * 发送HTTP PUT请求 + * + * @param urlPath + * 请求地址 + * @return 请求响应 + */ + public static String doPut(String urlPath) { + return HttpClientUtils.doRequest(urlPath, "PUT"); + } + + /** + * 发送HTTP DELETE请求 + * + * @param urlPath + * 访问URL地址 + * @param properties + * 请求参数 + * @return HTTP响应 + */ + public static String doDelete(String urlPath, Properties properties) { + return HttpClientUtils.doRequest(urlPath, properties, "DELETE"); + } + + /** + * 发送HTTP DELETE请求 + * + * @param urlPath + * 请求地址 + * @return 请求响应 + */ + public static String doDelete(String urlPath) { + return HttpClientUtils.doRequest(urlPath, "DELETE"); + } + + /** + * 发送HTTP请求 + * + * @param urlPath + * 请求地址 + * @param properties + * 请求参数 + * @param method + * 请求方法 + * @return 请求响应 + */ + public static String doRequest(String urlPath, Properties properties, String method) { + String retValue = null; + + // 检查参数 + if (StringUtils.isBlank(urlPath)) { + String message = "url path is blank."; + logger.error(message); + throw new RuntimeException(message); + } + if (StringUtils.isBlank(method)) { + String message = "method is blank."; + logger.error(message); + throw new RuntimeException(message); + } + // 请求参数类型转换 + String parameters = HttpClientUtils.getRequestParameters(properties); + // 生成最终访问地址 + urlPath = HttpClientUtils.getRequestUrl(urlPath, parameters, method); + + HttpURLConnection httpURLConnection = null; + try { + // 打开HTTP连接 + URL url = new URL(urlPath); + httpURLConnection = (HttpURLConnection) url.openConnection(); + httpURLConnection.setRequestMethod(method); + if ("POST".equals(method)) { + if (!parameters.isEmpty()) { + httpURLConnection.setDoOutput(true); + OutputStreamWriter out = new OutputStreamWriter(httpURLConnection.getOutputStream()); + BufferedWriter writer = new BufferedWriter(out); + // 添加参数到目标服务器 + writer.write(parameters); + writer.flush(); + writer.close(); + out.close(); + } + } + // 读取响应 + if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { + StringBuffer content = new StringBuffer(); + String line = ""; + BufferedReader in = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream())); + while ((line = in.readLine()) != null) { + content.append(line); + } + return content.toString(); + } else { + String message = "send http " + method + " request is failed, url = " + urlPath + ", parameters = " + + parameters; + message += ", response code = " + httpURLConnection.getResponseCode(); + logger.error(message); + throw new RuntimeException(message); + } + } catch (IOException e) { + String message = "send http " + method + " failed, url = " + urlPath + ", parameters = " + parameters; + logger.error(message, e); + } finally { + try { + if (httpURLConnection != null) { + httpURLConnection.disconnect(); + } + } catch (Exception e) { + String message = "disconnect http url connection failed, url = " + urlPath + ", parameters = " + + parameters; + logger.error(message, e); + } + } + + return retValue; + } + + /** + * 发送HTTP请求 + * + * @param urlPath + * 请求地址 + * @param method + * 请求方法 + * @return 请求响应 + */ + public static String doRequest(String urlPath, String method) { + return HttpClientUtils.doRequest(urlPath, null, method); + } + + /** + * 根据访问地址、请求参数和方法获取最终的请求访问地址 + * + * @param urlPath + * 访问地址 + * @param parameters + * 请求参数 + * @param method + * 请求方法 + * @return 最终的请求访问地址 + */ + public static String getRequestUrl(String urlPath, String parameters, String method) { + // 请求参数 + if ("GET".equals(method) || "PUT".equals(method) || "DELETE".equals(method)) { + if (!parameters.isEmpty()) { + if (urlPath.contains("?")) { + urlPath += "&" + parameters; + } else { + urlPath += "?" + parameters; + } + } + } + + return urlPath; + } + + /** + * 根据访问地址、请求参数和方法获取最终的请求访问地址 + * + * @param urlPath + * 访问地址 + * @param properties + * 请求参数 + * @param method + * 请求方法 + * @return 最终的请求访问地址 + */ + public static String getRequestUrl(String urlPath, Properties properties, String method) { + // 请求参数类型转换 + String parameters = HttpClientUtils.getRequestParameters(properties); + // 生成最终访问地址 + urlPath = HttpClientUtils.getRequestUrl(urlPath, parameters, method); + + return urlPath; + } + + /** + * 请求参数转换为字符串 + * + * @param properties + * 请求参数 + * @return 请求字符串 + */ + public static String getRequestParameters(Properties properties) { + String retValue = ""; + try { + if (properties != null && !properties.isEmpty()) { + Iterator> iterator = properties.entrySet().iterator(); + while (iterator.hasNext()) { + Entry entry = iterator.next(); + String key = (String) entry.getKey(); + String value = (String) entry.getValue(); + String parameter = key + "=" + URLEncoder.encode(value, "UTF-8"); + if (retValue.isEmpty()) { + retValue += parameter; + } else { + retValue += "&" + parameter; + } + } + } + } catch (UnsupportedEncodingException e) { + String message = "http request parameters UTF-8 encode failed."; + logger.error(message); + throw new RuntimeException(message); + } + + return retValue; + } + +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/HttpsClientUtils.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/HttpsClientUtils.java new file mode 100644 index 0000000..fcef195 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/HttpsClientUtils.java @@ -0,0 +1,140 @@ +package com.sinoparasoft.storage.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Properties; + +/** + * HTTPS客户端工具类 + * + * @author 袁涛 + * @date 2018.08.31 + */ +public class HttpsClientUtils { + private static final Logger logger = LoggerFactory.getLogger(HttpsClientUtils.class); + + /** + * 发送HTTP GET请求 + * + * @param urlPath + * 访问URL地址 + * @param properties + * 请求参数 + * @return HTTP响应 + */ + public static String doGet(String urlPath, Properties properties) { + return null; + } + + /** + * 发送HTTP GET请求 + * + * @param urlPath + * 请求地址 + * @return 请求响应 + */ + public static String doGet(String urlPath) { + return null; + } + + /** + * 发送HTTP POST请求 + * + * @param urlPath + * 访问URL地址 + * @param properties + * 请求参数 + * @return HTTP响应 + */ + public static String doPost(String urlPath, Properties properties) { + return null; + } + + /** + * 发送HTTP POST请求 + * + * @param urlPath + * 请求地址 + * @return 请求响应 + */ + public static String doPost(String urlPath) { + return null; + } + + /** + * 发送HTTP PUT请求 + * + * @param urlPath + * 访问URL地址 + * @param properties + * 请求参数 + * @return HTTP响应 + */ + public static String doPut(String urlPath, Properties properties) { + return null; + } + + /** + * 发送HTTP PUT请求 + * + * @param urlPath + * 请求地址 + * @return 请求响应 + */ + public static String doPut(String urlPath) { + return null; + } + + /** + * 发送HTTP DELETE请求 + * + * @param urlPath + * 访问URL地址 + * @param properties + * 请求参数 + * @return HTTP响应 + */ + public static String doDelete(String urlPath, Properties properties) { + return null; + } + + /** + * 发送HTTP DELETE请求 + * + * @param urlPath + * 请求地址 + * @return 请求响应 + */ + public static String doDelete(String urlPath) { + return null; + } + + /** + * 发送HTTP请求 + * + * @param urlPath + * 请求地址 + * @param properties + * 请求参数 + * @param method + * 请求方法 + * @return 请求响应 + */ + public static String doRequest(String urlPath, Properties properties, String method) { + return null; + } + + /** + * 发送HTTP请求 + * + * @param urlPath + * 请求地址 + * @param method + * 请求方法 + * @return 请求响应 + */ + public static String doRequest(String urlPath, String method) { + return null; + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/MD5Utils.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/MD5Utils.java new file mode 100644 index 0000000..a27408a --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/MD5Utils.java @@ -0,0 +1,29 @@ +package com.sinoparasoft.storage.utils; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * MD5工具类类 + * + * @author 袁涛 + * @date 2018.08.16 + */ +public class MD5Utils { + + /** + * 加密 + * + * @param data + * 原始数据 + * @return 加密后的数据 + * @throws NoSuchAlgorithmException + * @throws UnsupportedEncodingException + */ + public static String encode(String data) throws NoSuchAlgorithmException, UnsupportedEncodingException { + MessageDigest digest = MessageDigest.getInstance("MD5"); + digest.update(data.getBytes("UTF8")); + return StringUtils.bytesToString(digest.digest()); + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/StringUtils.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/StringUtils.java new file mode 100644 index 0000000..1e52ebe --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/utils/StringUtils.java @@ -0,0 +1,31 @@ +package com.sinoparasoft.storage.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 字符串工具类类 + * + * @author 袁涛 + * @date 2018.08.16 + */ +public class StringUtils { + private static final Logger logger = LoggerFactory.getLogger(StringUtils.class); + + /** + * 字节数组转为字符串 + * + * @param data + * 字节数组 + * @return 字符串 + */ + public static String bytesToString(byte[] data) { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < data.length; i++) { + buffer.append(Integer.toHexString((0x000000FF & data[i]) | 0xFFFFFF00) + .substring(6)); + } + + return buffer.toString(); + } +} diff --git a/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/web/ModelAndViewController.java b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/web/ModelAndViewController.java new file mode 100644 index 0000000..4fb7b84 --- /dev/null +++ b/hcframe-parent/storage/src/main/java/com/sinoparasoft/storage/web/ModelAndViewController.java @@ -0,0 +1,129 @@ +package com.sinoparasoft.storage.web; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import java.io.IOException; + +/** + * 模型视图控制器 + * + * @author 袁涛 + * + */ +@CrossOrigin +@Controller +@RequestMapping("/") +public class ModelAndViewController { + /** + * 获取首页面 + * + * @return 首页面 + * @throws IOException + */ + @RequestMapping(method = RequestMethod.GET, produces = "text/html") + public String index() { + return "redirect:/files/index"; + } + + @RequestMapping(value = "/fragments/aside", method = RequestMethod.GET, produces = "text/html") + public String aside() { + return "fragments/aside"; + } + + @RequestMapping(value = "/fragments/hamburger", method = RequestMethod.GET, produces = "text/html") + public String hamburger() { + return "fragments/hamburger"; + } + + @RequestMapping(value = "/fragments/breadcrumb", method = RequestMethod.GET, produces = "text/html") + public String breadcrumb() { + return "fragments/breadcrumb"; + } + + @RequestMapping(value = "/views/layout", method = RequestMethod.GET, produces = "text/html") + public String layout() { + return "layout"; + } + + @RequestMapping(value = "/fragments/navbar", method = RequestMethod.GET, produces = "text/html") + public String navbar() { + return "fragments/navbar"; + } + + /** + * 获取物理存储区管理主页 + * + * @return 物理存储区管理主页 + */ + @RequestMapping(value = "/regions/index", method = RequestMethod.GET, produces = "text/html") + public String storageRegionIndex(Model model) { + model.addAttribute("level1menu", "datas"); + model.addAttribute("level2menu", "regions"); + return "regions/index"; + } + + /** + * 获取逻辑存储区管理主页 + * + * @return 逻辑存储区管理主页 + */ + @RequestMapping(value = "/buckets/index", method = RequestMethod.GET, produces = "text/html") + public String bucketIndex(Model model) { + model.addAttribute("level1menu", "datas"); + model.addAttribute("level2menu", "buckets"); + return "buckets/index"; + } + + /** + * 获取数据管理主页 + * + * @return 数据管理主页 + */ + @RequestMapping(value = "/files/index", method = RequestMethod.GET, produces = "text/html") + public String fileIndex(Model model) { + model.addAttribute("level1menu", "datas"); + model.addAttribute("level2menu", "files"); + return "files/index"; + } + + /** + * 获取文件上传页面 + * + * @return 文件上传页面 + */ + @RequestMapping(value = "/files/upload", method = RequestMethod.GET, produces = "text/html") + public String fileUpload(Model model) { + model.addAttribute("level1menu", "datas"); + model.addAttribute("level2menu", "files"); + return "files/upload"; + } + + /** + * 获取文件批量上传页面 + * + * @return 文件批量上传页面 + */ + @RequestMapping(value = "/files/plupload", method = RequestMethod.GET, produces = "text/html") + public String filePlupload(Model model) { + model.addAttribute("level1menu", "datas"); + model.addAttribute("level2menu", "files"); + return "files/plupload"; + } + + /** + * 获取文件上传页面 + * + * @return 文件上传页面 + */ + @RequestMapping(value = "/files/elupload", method = RequestMethod.GET, produces = "text/html") + public String fileElupload(Model model) { + model.addAttribute("level1menu", "datas"); + model.addAttribute("level2menu", "files"); + return "files/elupload"; + } + +} diff --git a/hcframe-parent/storage/src/main/resources/application-iscas.yml b/hcframe-parent/storage/src/main/resources/application-iscas.yml new file mode 100644 index 0000000..0ec88cd --- /dev/null +++ b/hcframe-parent/storage/src/main/resources/application-iscas.yml @@ -0,0 +1,25 @@ +# data source properties +#spring.datasource.driverClassName=dm.jdbc.driver.DmDriver +#spring.datasource.url=jdbc\:dm\://192.168.100.179\:5236/STORAGE?useUnicode=true&characterEncoding=UTF-8 +#spring.datasource.username=STORAGE +#spring.datasource.password=123456789 +spring: + # data source properties + datasource: + driverClassName: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/storage?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false + username: root + password: root + dbcp2: + test-on-borrow: true + test-on-return: true + test-while-idle: true + time-between-eviction-runs-millis: 1800000 + num-tests-per-eviction-run: 3 + min-evictable-idle-time-millis: 1800000 + validation-query: SELECT 1 + servlet: + # file upload properties + multipart: + location: /Volumes/DATA/upload + diff --git a/hcframe-parent/storage/src/main/resources/application.yml b/hcframe-parent/storage/src/main/resources/application.yml new file mode 100644 index 0000000..a50ca38 --- /dev/null +++ b/hcframe-parent/storage/src/main/resources/application.yml @@ -0,0 +1,35 @@ +server: + port: 8094 +spring: + application: + name: storage + # jpa properties + jpa: + database: mysql + show-sql: true + generate-ddl: true + hibernate: + ddl-auto: update + naming: + implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl + physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl + properties: + hibernate: + dialect: org.hibernate.dialect.MySQL5InnoDBDialect + profiles: + active: iscas + # json date properties + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: GMT+8 + servlet: + # file upload properties + multipart: + enabled: true + max-file-size: 4096MB + max-request-size: 50MB +# logging properties +logging: + config: classpath:logback.xml +info: + author: 袁涛 diff --git a/hcframe-parent/storage/src/main/resources/create-db.sql b/hcframe-parent/storage/src/main/resources/create-db.sql new file mode 100644 index 0000000..335d964 --- /dev/null +++ b/hcframe-parent/storage/src/main/resources/create-db.sql @@ -0,0 +1,3 @@ +CREATE DATABASE `backend` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; +GRANT ALL ON *.* TO 'root'@'localhost' IDENTIFIED BY '123456'; +GRANT ALL ON *.* TO 'root'@'%' IDENTIFIED BY '123456'; diff --git a/hcframe-parent/storage/src/main/resources/ehcache.xml b/hcframe-parent/storage/src/main/resources/ehcache.xml new file mode 100644 index 0000000..97e00f8 --- /dev/null +++ b/hcframe-parent/storage/src/main/resources/ehcache.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/hcframe-parent/storage/src/main/resources/logback.xml b/hcframe-parent/storage/src/main/resources/logback.xml new file mode 100644 index 0000000..634c5c8 --- /dev/null +++ b/hcframe-parent/storage/src/main/resources/logback.xml @@ -0,0 +1,31 @@ + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + storage.%d{yyyy-MM-dd}.log + 30 + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{35} - %msg%n + + + + + + + + + + + + diff --git a/hcframe-parent/storage/src/main/resources/static/casAssets/images/casBack.png b/hcframe-parent/storage/src/main/resources/static/casAssets/images/casBack.png new file mode 100644 index 0000000000000000000000000000000000000000..831db5e96e2d4142c3d621c72cd48ca80bd88ce8 GIT binary patch literal 263934 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�Zu~EsPx-$?h`TZmnxFTp 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%0D{YT~lklZ{TDJx5)AkXWz zj1V9(9l{7-GfHIM$l*>bxG70tzRhBCwPKBpNC#~Xow6s3!BZvY zyqsA{g)kGrL1fed^k4g&v$^kKo<3k=&N_65NM?Y`g*5-0YsN-8CJerd^Ko-!6C2Of z*_=1XklR5~ZIrke2M-xn%mCn-1oJe*eaCZqPl`D9j_%^f&2peaP@Zx@+gGPj&iy@Q ze@GpT@s0-#IP&0^^W!dFm`@Md_W*DA4z%vHLA2yN`i5_Q^XvY=?t2a3!FJEKo$B;iANsYN2*Rm>ruTD;>7eO*uO&ANG|et0D~!69d)t39{`zn<{x*qL;oGxCl>- z?AI}>t`(io2Kfyd6qbn?@)X8yI%OWq(qpx1>YVo&7q)ZKW+j$_m0S&0vha;qse&XC z%#K(&kC2|>>SA+c>X%6$WZT0^Y#@OWxEwvW0b=kj4as@L#B-UgB5FpY7{*t&V7i+s z@*nzbdAL;W_GQ`a6G9L3k7_I!WkfF&J#a>u!uvGS*fFD6_k`5d=HxZc9$At7e4dq^ zv(Ws)moDG&09SWEt-}e{ecm`)b*gvv>DRqJ2-tnEG3ar}eMZ&&U$|?h<1NF5W_A)_ zyDhZ)MRqNtGc#lfY`59k&@0$1FN~^-_Q6Q>TKBGJb4GqE`rTv*qw@;e4My;Dk!n=3 z(-+-~tVioQt$9kTw#PqVNRVM@2>nGObJq2fkoZs8=RyUtfnPGCKC6^aT;1cH;%=)y zCDL0Z#x`ccGicb5eLYcJU7`Kz;5kAe7YQ~Ax`UKKPX0#K$S^Sw*_+z?OkV3If*o}1 zI9*bB4(Z^mHVAfD?hO!woPP_C6S~t?)$_XeG&&bw)-lI@MX{{kAw=i}Osn z*X+<=oA!yZZ5D7Zq-)s?td0R|6k4~Eg56=qu;5CNr(`3E&hsLQP^T1OND&L>N>Mn# zA=3?ZtGiYTkg>k^J~i0Qt$BvUM_eKXgl-~t9tZm8=t(X%h37~%M}#gG13ghOPYAaU z>eB^lshA&s3!eYjdw{|fmL+9SbB3LoiP>dl8YHKnx;GZxpHs2C;#%`@u=o3udPe`A zX6<bvo%>y=jv6lIP&=!*nHg#)Ber{ecdJM- zV7tw(XlR{o`O+`&k`B*7jGA<tlBt6( zk2K3*4FxVO69!?PZuA^nza?o9o?W4Uo4C5-RAwVM!-_5plath*A08I36|i_VU|N+E z0itGZs)8sxMvE;#H|1&TGn{hfht{3$c(Kf6umb;#25oHW);U|+jXGLYE7PHz9q7?jm3NMZxX!#^H;hV%jrmF7*)k%Ud3+Kn zmR3@bT`KchuhLFrC{i$u^SD7X2|xNWGbS@C&Zoj~tu(cvT>e#DS=(r^m}fxV>r5(dM0;rKuD(~o$e)I@i?_BW1|N~oPkpX&O%c?gpW z3)}r})#0!vtsBgJY~mK@!9{y+;wt~IeVhTqp~-da!|vKIwgGp#sb1G^`Lmn)O_2r8 z6#$*iPLWz18le5_IPi@wA0|;Kp6hNF5fw@JIA3n+7i1=yk1gK*W?8@rJx^C4u9-qHv;rmkm9$@$8 z>FbVHbDd$blR$k6yu-ck5w{q*%R}vCgX?Cn-8NoK)sCLC5@Y*ZT86=)_@0c{`}xhChcb+HbU6ORZ0fTAn@i-~m%hN=3>Vz|?YQ+(qP2B4q@~TyB|~lEk9pGXHBM*M-K(n7afcUN%SBv z4tzepkHlcj#TrJ*Vfr+*Ih`Kd*?vbz9Zu-;``F0yI@!&N~`3-)0B z_Rn(TnR|YK-4!RaTU@~#2gnh_^M*qn>AmP(@8Ft4Rf+MFhuYa0vXWyvX-eO14`;vs zrFAL}xqCSRu8J#{Buj!h8L1p%XsBjj-Buh{oGo3KblbhGSoJkv6D!fFuT?|J*!3XN z1tUnY11_kqQ5H8Ys6`5N(kX*13tj+2J_pM&wcU$IpK7dM_ot<`aNE_ z>F`{G?Q{s13$UFurS3$Hga5w&%ekzp4CC+AP-w+eINnr{okSsl|Ng5Do9j{Cu!H=> z9)>+sQi_;Lo1L9xQQQ>gJqGSQ9cjnz!r?i(7<+t#C14Ir6Ux-5ELWknXGwUVn>2xP zUZ^FaW+Fr6LOdq~?FC$@B7_cXs#GhP3~YJ7DlDORAcFxxTK>Bq+Q+X2ime2h3_t`u zp@papGksN(CAz{=4Ch`E4m`|Lm5XnYOSKhN+sUO8VBc~ry6fWwp8wU|;DpKr;O+r- zH=FCOdE$?RXjdBb38cH(3wIxzWHgltcn-mK!ce?E7Vm|_)RL4<7@Pz9;JnWhb;o~g zRwzHJxCxk3?Mw|;@0q>jeX3Iia`@s8gd?98l1ueQ(+u3wX*qWi?A2!nf$Wh!jHx8* zGaV}6hZBy78XA(OIlIUxgn&fZe)w!L&eHbV1X+?ci2hGY-H}~gf^n6|JdsjxmvFIs zD~h+3mxiZ2@OKDSpn8pI$Rn6uN-ly$b#r0KZ(oGnkk)~+_UBbu8eh!@vFK>H=Iy~1{iUFxi#nx^`uYXCRsZ}`H;j7sH3%K~gSXv%K?(U9C> z^InGVv_Bt>foxU^YDC!>04EhHw?%SeRl8OJRtG`YF2GR6R98tmW%yg2O$W}f(^clV z&l1uEEFv#*Pyz@p^5plAUcf zeSJ0%RxqkrFxBoz7&K8Q2u0H*DnrK2e%NDqA=*3e?0em5M*0<{?sLc81gb;9Brd%Q zye6%~8J7G-?yFwf2KOE9k{%A;-{+GZPvzM9#OuwOi$DLHlDr)EeSqEVr@pJ5bqP+o zAd^~3$}lzP@BhN*4aqaHT_0T6<#l=m@7$06a2+D9|2h=BwQs5 zN-H!GQp6DUds2-qJ#`M)wi_AP0HR1=#F3Gc5rkFw{8D#PP&#JJb0TJAg0)OD>0NFm zPF$Gc&Bw@ExWv>L)>rGF5~{n@s_Q01apzS%%r0&Vy=I?c_tBmriE;nx(sAUu#a1la z`KVylbq~Ju0J~2b3>P}nF?m+ zt_il2A^&xgCp+N6I0UaFcd~t=4Sx>B<6iM@9n>2_Xrp)Z=Gpu*8S}Dbe7hwGly>cy9@^?$BvQ1p;C8KF} zI_q<}#e8MCSyXo)PDfnWhtax=8vm92RlUswKpg4`tYbQNA+4KouMhFAcX7I^*Z%;! zPaPYdeBukzqbh&Yn@YQ0qOq?(7#S7ODz+1^yqy@KbwLQ8h>iBZ|GA}g+Qh*PH(|VI zl4pPS_o!d5AYnxj#`oLzhEiQ+cGJa1T0IyIw9|;9!^!3Q#r36-pb$EA4h7~?iIR)j zy%sA+LwR<-<0ZI()k1{hmO!`u=`jr4B@O8Q2efVo)`M^oYnvb6v7;gq)Q zk-k!$hZ(umW6bJvAfFVNnKQT9+bp);C4lj6T6b$d=>&&SFJg&%Xx)SAc$?Q1LuO~; z=vCNmp408|`X6BT*(2mzPJcmebiHuGZ)o*v4MwHN?dZG=*v|Si4Y(64Q#ai*vN`qt zY-!z}kM_LZ95yR&r^fr=3x|*DkfhDNT9c5e2v;Y1^jMnC5@pw#ajNAkq03A9hhnum zqvudseIso|&YLz5OtL()y_lMGW~M8fE$fAvxs~rolv@vTivb8BNg_vnp&qQ2b{A6j=B57-av z)+Mv4P91E9(=GJn13GVulUMaGp1xz*~bYNP^M1MZM1ZOQCP_*Oi(u7||l|r0wJro8V zj?VPMT;A0Lufv{2ot6&1XqBjQ&9PdHf{%fd2i2W(2iI#Ey-CmLxecN3z2#4(b-1Lp z>%Nh~{$xZK;QE8@D(P?;bvrsbNB{Ys|9d>^PbCH4cO4HX`t~QqWd|cs_%xTK5GPMo ztbjY=@@F?FFx+D7V162Y)V$Ztg&XhF9s2iwTSnW~&{yO4&7nS2)j)3|ieP--^oOZh zOA**1y-Ch1W(h)a8;GuFC!XUnJ)`T+5oey1n(SubqD&&e{vxP`;^ij9DQPFQuspjP zKzx79MotK6He}M+!rhhWCaTR**s=y4X6LXVnE0(u2OMM-Pq5(Do<7?(<2(r(ey3h;Fk&`|`oa#bHs{jt;n! z4Yjjy-k9I1;&16H$D!TfPaGVqkIeT!;duRfYKQ265)|Xx{s(3)I@9mea2Y|YF?7$I zm@%me9jK!R55rUl0#(I{4`Fj@k9ohoOH4GYAEd@MBdEG|UixQp&qRtVl7oAR!$^7- zMa}>){pH$1u7^u$Q@GqDh%habGusE!ux`JVe6gSL_pAV~o*qalY?r=*!b!gY)yenK zx+@qzu5+m;GP}jJ?(uWxjOUQ>y2T-Em#<*;&wu{&KTn4JmyMjeU)eKb-g1TZyeimE zg2dMDPj3fPYE~Thq-JHdZdv8BJOj`DocwR<>+8J-;9eJ-5<2|5^O$}+r1W;_u_BFN zh3iPR0eN0GYTSAH-a$x7K}4UWskC)M$B@I|e4wxzlY+?y&>?ZTiHJ5gtrdjdp2di{ zw+U8pf~fQ7<2yv5lAwDEnF4RD9xFsLFUaD6l8c;_pMY32s>^w!ZWXP2iq`G5oWha zxjOpt@u=+JWXjt~5O62E$(@X-PNBgL4W5(kZd>OFQFXkCcO6&uBK6n&8uWLUquhy;4 zGizzbRk599d9o5kye~!@2AbJ*|b9QLcZ`=3MUa%Q|=L_a;{;<Iv%>ADW)@2#|Ng@&@JaS5O^f zY0BR9m$sLsb(bjeb-hKqp4%3Bov|D~)t^_{Z1yM@>08Fl1z*(~b`SFT$g%XiuCi=+ zzdbw;rqkQMvS3l}TOGLz6czfcS2II2+_?SIimGd4;)eGL!h6N*xjO^_cM$WVzAeYr zZ8vrQm>rm{Hcr<=LuF7irMC)EcvV6tblIj9(&cB*m2>?#vPxXrb}wQ#q#46OhAbj+ zUx(1Kt>;xx45cTeqNfUib*4GOiDgj9zhUEZCVfEBy6KpZ*@NhgX~%r59KSr(C9OWU z`kDC&nI(5hK{~M@RuE*@?QBA~e<|CB(3v~GQf{phcz>G3M0JRR?6?TKxT;`9 z7I^F_YO=v{_n+od?)TU#>6ARCpQ2dMf%R|^Dfl34PNj8B*f$5aeL?Kwwgi{xiU`J4 zm0>00!lCuR4Y@ORL^>LhRALar2Qq`3t08y0b}bA4tz4ey_L#cs5W5zitCp=;d5~)M ztGure{u`J5xWN%W%?ra#u5&!c;tJ;vt$Vvw?*exE5Q~3bOH^W?mV6!v+WC;7Kp*s6LHVDtzK{|wIN7czRxf4%jLdC#rnoY5q+Q6cD zrnGcL3HB9`A?d4%FFSzJm5}jPLPEOu>+OMv-Rwgm0RXUS*yYy^Nr|a-Nvt@m)RcC? zfnq-;+DwIILJq|Xdkj7!wk?k0*uTbDzBWN&^*FJVyo+wE-z3$Lx>Z17r&{Hk^^mT2 z&^NB?^$yLh?`V!Sl|yhpleoL5zgi+zKa*3;$j~kUb`J!42J=V19!U4R&K-|M%9Ew9 zT0W8$02ZWwnqN?p(}}RCZW~M|Ej6mxbmk(Zq4d@! zF%N*US=4l1F*9tUV`AC(J{QkTcwDoAc$Zs_P7qZR)#1(Eu5W0(Ph5^;S8M7Wn*G#K zS;uy3D}3V0#&&s^ekriix8Kgz^#mgTg{#~ zW!|3FU63T~1a^1F6MQ6Hvd;;??kW?&^Lo1FJ&(HQ^%%;Y0jAaR9z3}l>#YUkPP6S^ zs;p+HZn#ZNv7Ma{YrXFdKFG-a{Xd!(Nu*=dY(~ujObS07>!Gt#$pvKCUko_*LONN( z>1-KPAJXOQDUly_)eoAFL3j)(iCtjgW~D3u3|CY)AiM{{@`2B)vK_y3W!Zhcv5RyPe+V80x8a{=u|P-*}=) zV5iqG!5s~u#!YCP4jbL(8-d-8r;x9BeNXE?knVZC$5ynu`<{Ti&>+1yyG;oR0#v30FV@pZb&N{gzMShQa(GdsoUz+3~vtt1dA zm=kj_t~R=JB9XQfpof5m@tL7nS-`A)#21L=AcS{KU_eHwE#cTzV#O4p!_+vN8O}?@ zV)s0)wEmUCX5D{*CqCG-*q$qg)E&C)|L`1G9N4US;ih`OKd2|(^Wzh)?Wh@St=BWb zN)tGoj@UQ2(^~_(J54rE<9#@Ld0rp>!d1rD?tnWfkUKZvZe(A+5=C>}U6Ht);+Z+H zRcsgM#!5==yc-|4?$DJz)s{>4%wRlZTm$^b@*|`qFYe}7m-BECTPn^ve+ub*g#<{R zsGBOEa-n}VDTLcs_OT8ibjAt&`PL13M0!u0JO()H$HH;A_Q0nuYHFFPC3ttu)hDM4 zycgA7V_~XSFuo5!b-S3wg_`OceCS6O_9#0k8^7Mz3N2K}e2MsV|4V?~hgkh{Q6IGc zn7Ntwv!RDssGU{+D=M2uuZAECAzUz6RX#NW^Sw&I`eSj#=scXE^R=2BFRr9ciWFtjCyz_Y`6VKrOl+Rm#&M%WQEC%weDxQFVj~I`JJ%k z?TU7?dc{d;Nz4=iLv(yLq6(B?D`Le8F|gPKq?061mP({8LOOWf1~0-8r7HU%BKB`U z9>w;V$U6NHMi!%R*>v^Bg%1tfiqv4z0oxU3Fg-`=(T%XbK0O{zclCw)`$Zh|GOhLD z#gTBZ!F-2Pwj0=~+^bGP=5~uOS}4-2akn3>&26ock|dzVsbYTaJL8B zZU5XNyzy+KR7DZh9h)1gg~f@UK5{v~5rvWBbGRs+B;#~ZFrEdiR&zQF5~h%Dyl1<> zTo}NH;6@|)RVQvSU`}b=5VGz@fn}g9rb#Lb?~u7DJQu(WhN~s_u@4cH_Gb6h`3u^; zsM#w@fpyLOpt^f3y)IL^_;+_4cWZj!__@02;Vf%;cO&Xsj<4l!--+3+rgi=i9$@!L zuZPP#tB}W3KCGvvU8C*`lL2>@k7Wd*seR%qwsU!0dp7Sqn7VcDZnfN46|2;r1n`bp zkLb+c)WzmJRU0dgTcV2Dr7{A9uqmQCY26-Ngjx_x=ZhsEYevLU22M;I5ljbAz@a-} zelgJoI*g8x;q|_SsSXFawhA7J-IgXVdC#VX`6n-A|Pc}uEn zMDFU?PC^X|;iM!)D(Vw~5``Ubr}ke-%$+NWE8~rdQQ~gFN@m{Z7nJS-9bIMZM{>Gx zxecNm8%#hKak`|unGyIFvn`9JImPTE?St`F>yQo!hD)F=_=wAx=4HAT;A}7Zf-s*8 zAMkhBgX6@CW|h-S#JE*|URt;U(KDK)bl8W}-E8S~=H*>85lKJUML0XK?mHZ=eZWr3 jU(##c@bQ=P{{jpEfQF94!IoV<00000NkvXXu0mjf%~j0u literal 0 HcmV?d00001 diff --git a/hcframe-parent/storage/src/main/resources/static/casAssets/images/casBackBody.png b/hcframe-parent/storage/src/main/resources/static/casAssets/images/casBackBody.png new file mode 100644 index 0000000000000000000000000000000000000000..3452044e9cd0ac6d748b12cbd259340bf341fd2a GIT binary patch literal 523233 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