├── .dart_tool └── package_config.json ├── .gitignore ├── CHANGELOG.md ├── README.md ├── analysis_options.yaml ├── bin └── dart_mars.dart ├── lib ├── helper │ ├── CompileHelper.dart │ ├── CreateHelper.dart │ ├── GetHelper.dart │ ├── Helper.dart │ ├── PackageHelper.dart │ ├── RunHelper.dart │ ├── ServeHelper.dart │ ├── WelcomeHelper.dart │ └── serve │ │ ├── DataBaseHelper.dart │ │ ├── DataFieldHelper.dart │ │ └── RouteConfigHelper.dart └── template │ ├── Pubspec.dart │ ├── app │ ├── config │ │ ├── ConfigContext.dart │ │ ├── ConfigDatabase.dart │ │ ├── ConfigHook.dart │ │ ├── ConfigLog.dart │ │ └── ConfigRoute.dart │ └── controller │ │ └── HomeController.dart │ ├── bin │ └── Bin.dart │ ├── bootstrap │ ├── App.dart │ ├── Context.dart │ ├── Server.dart │ ├── crypto │ │ ├── AES.dart │ │ ├── RSA.dart │ │ ├── Sha1WithRSA.dart │ │ ├── Sha256WithRSA.dart │ │ └── ShaRsaHelper.dart │ ├── db │ │ ├── Db.dart │ │ ├── DbColumn.dart │ │ ├── DbConfig.dart │ │ ├── DbConnection.dart │ │ ├── DbRaw.dart │ │ └── DbSqlBuilder.dart │ ├── helper │ │ ├── CommonHelper.dart │ │ ├── ConvertHelper.dart │ │ ├── ListHelper.dart │ │ ├── LogHelper.dart │ │ ├── PrintHelper.dart │ │ ├── RequestHelper.dart │ │ ├── RouteHelper.dart │ │ ├── TransHelper.dart │ │ └── VerifyHelper.dart │ ├── meta │ │ ├── FieldMeta.dart │ │ ├── RouteMeta.dart │ │ └── TableMeta.dart │ ├── model │ │ ├── FormData.dart │ │ └── UploadFile.dart │ └── redis │ │ └── Redis.dart │ ├── env │ └── Env.dart │ └── extend │ └── model │ └── Agent.dart ├── pubspec.lock ├── pubspec.yaml └── test ├── check.dart ├── test.dart └── test_async.dart /.dart_tool/package_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "configVersion": 2, 3 | "packages": [ 4 | { 5 | "name": "_fe_analyzer_shared", 6 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/_fe_analyzer_shared-22.0.0", 7 | "packageUri": "lib/", 8 | "languageVersion": "2.12" 9 | }, 10 | { 11 | "name": "analyzer", 12 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/analyzer-1.7.0", 13 | "packageUri": "lib/", 14 | "languageVersion": "2.12" 15 | }, 16 | { 17 | "name": "args", 18 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/args-2.1.1", 19 | "packageUri": "lib/", 20 | "languageVersion": "2.12" 21 | }, 22 | { 23 | "name": "async", 24 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/async-2.7.0", 25 | "packageUri": "lib/", 26 | "languageVersion": "2.12" 27 | }, 28 | { 29 | "name": "boolean_selector", 30 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/boolean_selector-2.1.0", 31 | "packageUri": "lib/", 32 | "languageVersion": "2.12" 33 | }, 34 | { 35 | "name": "charcode", 36 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/charcode-1.3.1", 37 | "packageUri": "lib/", 38 | "languageVersion": "2.12" 39 | }, 40 | { 41 | "name": "cli_util", 42 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/cli_util-0.3.1", 43 | "packageUri": "lib/", 44 | "languageVersion": "2.12" 45 | }, 46 | { 47 | "name": "collection", 48 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/collection-1.15.0", 49 | "packageUri": "lib/", 50 | "languageVersion": "2.12" 51 | }, 52 | { 53 | "name": "convert", 54 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/convert-3.0.1", 55 | "packageUri": "lib/", 56 | "languageVersion": "2.12" 57 | }, 58 | { 59 | "name": "coverage", 60 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/coverage-1.0.3", 61 | "packageUri": "lib/", 62 | "languageVersion": "2.12" 63 | }, 64 | { 65 | "name": "crypto", 66 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/crypto-3.0.1", 67 | "packageUri": "lib/", 68 | "languageVersion": "2.12" 69 | }, 70 | { 71 | "name": "file", 72 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/file-6.1.2", 73 | "packageUri": "lib/", 74 | "languageVersion": "2.12" 75 | }, 76 | { 77 | "name": "frontend_server_client", 78 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/frontend_server_client-2.1.0", 79 | "packageUri": "lib/", 80 | "languageVersion": "2.12" 81 | }, 82 | { 83 | "name": "glob", 84 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/glob-2.0.1", 85 | "packageUri": "lib/", 86 | "languageVersion": "2.12" 87 | }, 88 | { 89 | "name": "http_multi_server", 90 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/http_multi_server-3.0.1", 91 | "packageUri": "lib/", 92 | "languageVersion": "2.12" 93 | }, 94 | { 95 | "name": "http_parser", 96 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/http_parser-4.0.0", 97 | "packageUri": "lib/", 98 | "languageVersion": "2.12" 99 | }, 100 | { 101 | "name": "io", 102 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/io-1.0.0", 103 | "packageUri": "lib/", 104 | "languageVersion": "2.12" 105 | }, 106 | { 107 | "name": "js", 108 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/js-0.6.3", 109 | "packageUri": "lib/", 110 | "languageVersion": "2.12" 111 | }, 112 | { 113 | "name": "logging", 114 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/logging-1.0.1", 115 | "packageUri": "lib/", 116 | "languageVersion": "2.12" 117 | }, 118 | { 119 | "name": "matcher", 120 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/matcher-0.12.10", 121 | "packageUri": "lib/", 122 | "languageVersion": "2.12" 123 | }, 124 | { 125 | "name": "meta", 126 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/meta-1.4.0", 127 | "packageUri": "lib/", 128 | "languageVersion": "2.12" 129 | }, 130 | { 131 | "name": "mime", 132 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/mime-1.0.0", 133 | "packageUri": "lib/", 134 | "languageVersion": "2.12" 135 | }, 136 | { 137 | "name": "mysql1", 138 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/mysql1-0.19.2", 139 | "packageUri": "lib/", 140 | "languageVersion": "2.12" 141 | }, 142 | { 143 | "name": "node_preamble", 144 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/node_preamble-2.0.1", 145 | "packageUri": "lib/", 146 | "languageVersion": "2.12" 147 | }, 148 | { 149 | "name": "package_config", 150 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/package_config-2.0.0", 151 | "packageUri": "lib/", 152 | "languageVersion": "2.12" 153 | }, 154 | { 155 | "name": "path", 156 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/path-1.8.0", 157 | "packageUri": "lib/", 158 | "languageVersion": "2.12" 159 | }, 160 | { 161 | "name": "pedantic", 162 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/pedantic-1.11.1", 163 | "packageUri": "lib/", 164 | "languageVersion": "2.12" 165 | }, 166 | { 167 | "name": "pool", 168 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/pool-1.5.0", 169 | "packageUri": "lib/", 170 | "languageVersion": "2.12" 171 | }, 172 | { 173 | "name": "process_run", 174 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/process_run-0.12.1+1", 175 | "packageUri": "lib/", 176 | "languageVersion": "2.12" 177 | }, 178 | { 179 | "name": "pub_semver", 180 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/pub_semver-2.0.0", 181 | "packageUri": "lib/", 182 | "languageVersion": "2.12" 183 | }, 184 | { 185 | "name": "shelf", 186 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/shelf-1.1.4", 187 | "packageUri": "lib/", 188 | "languageVersion": "2.12" 189 | }, 190 | { 191 | "name": "shelf_packages_handler", 192 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/shelf_packages_handler-3.0.0", 193 | "packageUri": "lib/", 194 | "languageVersion": "2.12" 195 | }, 196 | { 197 | "name": "shelf_static", 198 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/shelf_static-1.0.0", 199 | "packageUri": "lib/", 200 | "languageVersion": "2.12" 201 | }, 202 | { 203 | "name": "shelf_web_socket", 204 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/shelf_web_socket-1.0.1", 205 | "packageUri": "lib/", 206 | "languageVersion": "2.12" 207 | }, 208 | { 209 | "name": "source_map_stack_trace", 210 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/source_map_stack_trace-2.1.0", 211 | "packageUri": "lib/", 212 | "languageVersion": "2.12" 213 | }, 214 | { 215 | "name": "source_maps", 216 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/source_maps-0.10.10", 217 | "packageUri": "lib/", 218 | "languageVersion": "2.12" 219 | }, 220 | { 221 | "name": "source_span", 222 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/source_span-1.8.1", 223 | "packageUri": "lib/", 224 | "languageVersion": "2.12" 225 | }, 226 | { 227 | "name": "stack_trace", 228 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/stack_trace-1.10.0", 229 | "packageUri": "lib/", 230 | "languageVersion": "2.12" 231 | }, 232 | { 233 | "name": "stream_channel", 234 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/stream_channel-2.1.0", 235 | "packageUri": "lib/", 236 | "languageVersion": "2.12" 237 | }, 238 | { 239 | "name": "string_scanner", 240 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/string_scanner-1.1.0", 241 | "packageUri": "lib/", 242 | "languageVersion": "2.12" 243 | }, 244 | { 245 | "name": "synchronized", 246 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/synchronized-3.0.0", 247 | "packageUri": "lib/", 248 | "languageVersion": "2.12" 249 | }, 250 | { 251 | "name": "term_glyph", 252 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/term_glyph-1.2.0", 253 | "packageUri": "lib/", 254 | "languageVersion": "2.12" 255 | }, 256 | { 257 | "name": "test", 258 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/test-1.17.9", 259 | "packageUri": "lib/", 260 | "languageVersion": "2.12" 261 | }, 262 | { 263 | "name": "test_api", 264 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/test_api-0.4.1", 265 | "packageUri": "lib/", 266 | "languageVersion": "2.12" 267 | }, 268 | { 269 | "name": "test_core", 270 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/test_core-0.3.29", 271 | "packageUri": "lib/", 272 | "languageVersion": "2.12" 273 | }, 274 | { 275 | "name": "typed_data", 276 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/typed_data-1.3.0", 277 | "packageUri": "lib/", 278 | "languageVersion": "2.12" 279 | }, 280 | { 281 | "name": "vm_service", 282 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/vm_service-7.1.0", 283 | "packageUri": "lib/", 284 | "languageVersion": "2.12" 285 | }, 286 | { 287 | "name": "watcher", 288 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/watcher-1.0.0", 289 | "packageUri": "lib/", 290 | "languageVersion": "2.12" 291 | }, 292 | { 293 | "name": "web_socket_channel", 294 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/web_socket_channel-2.1.0", 295 | "packageUri": "lib/", 296 | "languageVersion": "2.12" 297 | }, 298 | { 299 | "name": "webkit_inspection_protocol", 300 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/webkit_inspection_protocol-1.0.0", 301 | "packageUri": "lib/", 302 | "languageVersion": "2.12" 303 | }, 304 | { 305 | "name": "yaml", 306 | "rootUri": "file:///C:/Users/tangpanqing/AppData/Local/Pub/Cache/hosted/pub.flutter-io.cn/yaml-3.1.0", 307 | "packageUri": "lib/", 308 | "languageVersion": "2.12" 309 | }, 310 | { 311 | "name": "dart_mars", 312 | "rootUri": "../", 313 | "packageUri": "lib/", 314 | "languageVersion": "2.10" 315 | } 316 | ], 317 | "generated": "2021-08-17T04:23:48.632825Z", 318 | "generator": "pub", 319 | "generatorVersion": "2.14.0-46.0.dev" 320 | } 321 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .dart_tool/ 3 | .dart_tool/package_config.json 4 | .packages 5 | 6 | # Conventional directory for build outputs 7 | build/ 8 | 9 | # Directory created by dartdoc 10 | doc/api/ 11 | pubspec.lock 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 2 | 3 | - Initial version, created by Stagehand 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## DartMars是什么 2 | 3 | `DartMars` 是服务端开发框架,能够帮助开发者以 `Dart` 语言为基础,快速开发服务端应用。 4 | 5 | [中文文档](https://tangpanqing.github.io/dart_mars_docs/zh/) 6 | 7 | ## 开始一个项目如此简单 8 | 9 | ``` 10 | # 安装DartMars 11 | dart pub global activate --source git https://github.com/tangpanqing/dart_mars.git 12 | 13 | # 创建项目 14 | dart pub global run dart_mars --create project_name 15 | 16 | # 进入目录 17 | cd project_name 18 | 19 | # 获取依赖 20 | dart pub global run dart_mars --get 21 | 22 | # 启动项目 23 | dart pub global run dart_mars --serve dev 24 | ``` -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Defines a default set of lint rules enforced for 2 | # projects at Google. For details and rationale, 3 | # see https://github.com/dart-lang/pedantic#enabled-lints. 4 | include: package:pedantic/analysis_options.yaml 5 | 6 | # For lint rules and documentation, see http://dart-lang.github.io/linter/lints. 7 | # Uncomment to specify additional rules. 8 | # linter: 9 | # rules: 10 | # - camel_case_types 11 | 12 | analyzer: 13 | # exclude: 14 | # - path/to/excluded/files/** 15 | errors: 16 | omit_local_variable_types: ignore -------------------------------------------------------------------------------- /bin/dart_mars.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_mars/helper/WelcomeHelper.dart'; 2 | import 'package:dart_mars/helper/CreateHelper.dart'; 3 | import 'package:dart_mars/helper/GetHelper.dart'; 4 | import 'package:dart_mars/helper/ServeHelper.dart'; 5 | import 'package:dart_mars/helper/CompileHelper.dart'; 6 | import 'package:dart_mars/helper/RunHelper.dart'; 7 | import 'package:dart_mars/helper/Helper.dart'; 8 | 9 | void main(List arguments) async { 10 | if (arguments.isEmpty) return WelcomeHelper.run(); 11 | 12 | if (arguments[0] == '--create') return CreateHelper.run(arguments[1]); 13 | 14 | if (arguments[0] == '--get') return GetHelper.run(); 15 | 16 | if (arguments[0] == '--serve') { 17 | await ServeHelper.run(arguments); 18 | return; 19 | } 20 | 21 | if (arguments[0] == '--compile') return CompileHelper.run(arguments[1]); 22 | 23 | if (arguments[0] == '--run') return RunHelper.run(arguments[1]); 24 | 25 | if (arguments[0] == '--help') return Helper.run(); 26 | } 27 | -------------------------------------------------------------------------------- /lib/helper/CompileHelper.dart: -------------------------------------------------------------------------------- 1 | import 'package:process_run/shell.dart'; 2 | import 'PackageHelper.dart'; 3 | 4 | class CompileHelper { 5 | static void run(String type) { 6 | if (!PackageHelper.typeList.contains(type)) { 7 | print('compile type only accect value from ' + 8 | PackageHelper.typeList.join(',')); 9 | } else { 10 | if ('aot' == type || 'jit' == type) type += '-snapshot'; 11 | var str = 12 | 'dart compile $type bin/' + PackageHelper.getPackageName() + '.dart'; 13 | Shell().run(str); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/helper/CreateHelper.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import '../template/bootstrap/crypto/AES.dart'; 4 | import '../template/bootstrap/crypto/RSA.dart'; 5 | import '../template/bootstrap/crypto/Sha1WithRSA.dart'; 6 | import '../template/bootstrap/crypto/Sha256WithRSA.dart'; 7 | import '../template/bootstrap/crypto/ShaRsaHelper.dart'; 8 | 9 | import '../template/app/config/ConfigContext.dart'; 10 | import '../template/app/config/ConfigDatabase.dart'; 11 | import '../template/app/config/ConfigHook.dart'; 12 | import '../template/app/config/ConfigLog.dart'; 13 | import '../template/app/config/ConfigRoute.dart'; 14 | 15 | import '../template/app/controller/HomeController.dart'; 16 | 17 | import '../template/bootstrap/db/Db.dart'; 18 | import '../template/bootstrap/db/DbConfig.dart'; 19 | import '../template/bootstrap/db/DbConnection.dart'; 20 | import '../template/bootstrap/db/DbSqlBuilder.dart'; 21 | import '../template/bootstrap/db/DbColumn.dart'; 22 | import '../template/bootstrap/db/DbRaw.dart'; 23 | 24 | import '../template/bootstrap/redis/Redis.dart'; 25 | 26 | import '../template/bootstrap/helper/LogHelper.dart'; 27 | import '../template/bootstrap/helper/CommonHelper.dart'; 28 | import '../template/bootstrap/helper/ConvertHelper.dart'; 29 | import '../template/bootstrap/helper/PrintHelper.dart'; 30 | import '../template/bootstrap/helper/RequestHelper.dart'; 31 | import '../template/bootstrap/helper/RouteHelper.dart'; 32 | import '../template/bootstrap/helper/VerifyHelper.dart'; 33 | import '../template/bootstrap/helper/TransHelper.dart'; 34 | import '../template/bootstrap/helper/ListHelper.dart'; 35 | 36 | import '../template/bootstrap/meta/RouteMeta.dart'; 37 | import '../template/bootstrap/meta/TableMeta.dart'; 38 | import '../template/bootstrap/meta/FieldMeta.dart'; 39 | 40 | import '../template/bootstrap/model/FormData.dart'; 41 | import '../template/bootstrap/model/UploadFile.dart'; 42 | 43 | import '../template/bootstrap/App.dart'; 44 | import '../template/bootstrap/Context.dart'; 45 | import '../template/bootstrap/Server.dart'; 46 | 47 | import '../template/bin/Bin.dart'; 48 | import '../template/extend/model/Agent.dart'; 49 | 50 | import '../template/env/Env.dart'; 51 | import '../template/Pubspec.dart'; 52 | 53 | class CreateHelper { 54 | static Map fileMap = { 55 | /// readme 56 | 'README.md': '# {package}', 57 | 58 | /// pubspec 59 | 'pubspec.yaml': Pubspec.content, 60 | 61 | /// bin 62 | 'bin/{package}.dart': Bin.content, 63 | 64 | /// devops 65 | 'devops/.gitkeep': '', 66 | 67 | /// public 68 | 'public/hello.html': '

hello world

', 69 | 'public/uploads/.gitkeep': '', 70 | 71 | /// env 72 | 'env/dev.yaml': Env.content, 73 | 'env/test.yaml': Env.content, 74 | 'env/prod.yaml': Env.content, 75 | 76 | /// cert 77 | 'cert/key.pem': '', 78 | 'cert/cert.pem': '', 79 | 80 | /// log 81 | 'log/.gitkeep': '', 82 | 83 | /// bootstrap 84 | 'lib/bootstrap/App.dart': App.content, 85 | 'lib/bootstrap/Server.dart': Server.content, 86 | 'lib/bootstrap/Context.dart': Context.content, 87 | 88 | /// bootstrap db 89 | 'lib/bootstrap/db/Db.dart': Db.content, 90 | 'lib/bootstrap/db/DbColumn.dart': DbColumn.content, 91 | 'lib/bootstrap/db/DbConfig.dart': DbConfig.content, 92 | 'lib/bootstrap/db/DbConnection.dart': DbConnection.content, 93 | 'lib/bootstrap/db/DbRaw.dart': DbRaw.content, 94 | 'lib/bootstrap/db/DbSqlBuilder.dart': DbSqlBuilder.content, 95 | 96 | /// bootstrap redis 97 | 'lib/bootstrap/redis/Redis.dart': Redis.content, 98 | 99 | /// bootstrap helper 100 | 'lib/bootstrap/helper/CommonHelper.dart': CommonHelper.content, 101 | 'lib/bootstrap/helper/ConvertHelper.dart': ConvertHelper.content, 102 | 'lib/bootstrap/helper/LogHelper.dart': LogHelper.content, 103 | 'lib/bootstrap/helper/PrintHelper.dart': PrintHelper.content, 104 | 'lib/bootstrap/helper/RequestHelper.dart': RequestHelper.content, 105 | 'lib/bootstrap/helper/RouteHelper.dart': RouteHelper.content, 106 | 'lib/bootstrap/helper/VerifyHelper.dart': VerifyHelper.content, 107 | 'lib/bootstrap/helper/TransHelper.dart': TransHelper.content, 108 | 'lib/bootstrap/helper/ListHelper.dart': ListHelper.content, 109 | 110 | /// bootstrap crypto 111 | 'lib/bootstrap/crypto/AES.dart': AES.content, 112 | 'lib/bootstrap/crypto/RSA.dart': RSA.content, 113 | 'lib/bootstrap/crypto/Sha1WithRSA.dart': Sha1WithRSA.content, 114 | 'lib/bootstrap/crypto/Sha256WithRSA.dart': Sha256WithRSA.content, 115 | 'lib/bootstrap/crypto/ShaRsaHelper.dart': ShaRsaHelper.content, 116 | 117 | /// bootstrap meta 118 | 'lib/bootstrap/meta/RouteMeta.dart': RouteMeta.content, 119 | 'lib/bootstrap/meta/TableMeta.dart': TableMeta.content, 120 | 'lib/bootstrap/meta/FieldMeta.dart': FieldMeta.content, 121 | 122 | /// bootstrap model 123 | 'lib/bootstrap/model/FormData.dart': FormData.content, 124 | 'lib/bootstrap/model/UploadFile.dart': UploadFile.content, 125 | 126 | /// config 127 | 'lib/config/context.dart': ConfigContext.content, 128 | 'lib/config/database.dart': ConfigDatabase.content, 129 | 'lib/config/hook.dart': ConfigHook.content, 130 | 'lib/config/log.dart': ConfigLog.content, 131 | 'lib/config/route.dart': ConfigRoute.content, 132 | 133 | /// controller 134 | 'lib/app/controller/HomeController.dart': HomeController.content, 135 | 136 | /// extend 137 | 'lib/extend/.gitkeep': '', 138 | 'lib/extend/model/Agent.dart': Agent.content, 139 | 140 | /// tests 141 | 'lib/tests/test_main.dart': ''' 142 | void main(){ 143 | print('you can do some test in here'); 144 | } 145 | ''', 146 | }; 147 | 148 | static void run(String package) { 149 | var path = Directory.current.path.replaceAll('\\', '/'); 150 | var project = path + '/' + package; 151 | if (!Directory(project).existsSync()) { 152 | Directory(project).createSync(); 153 | } else { 154 | print('dir ' + 155 | package + 156 | ' is already exists, please chose other or delete it then try again'); 157 | return; 158 | } 159 | 160 | fileMap.forEach((filePath, fileContent) { 161 | var filePathArr = filePath.split('/'); 162 | for (var i = 0; i < filePathArr.length; i++) { 163 | var path = project + '/' + filePathArr.getRange(0, i + 1).join('/'); 164 | path = path.replaceAll('{package}', package); 165 | fileContent = fileContent.replaceAll('{package}', package); 166 | fileContent = 167 | fileContent.replaceAll('{time}', DateTime.now().toString()); 168 | 169 | if (!path.contains('.')) { 170 | var directory = Directory(path); 171 | if (!Directory(path).existsSync()) directory.createSync(); 172 | } else { 173 | var file = File(path); 174 | if (!file.existsSync()) file.createSync(); 175 | file.writeAsStringSync(fileContent); 176 | } 177 | } 178 | }); 179 | 180 | print('project ' + package + ' has been created'); 181 | print('you can change dir with command: cd ' + package); 182 | print( 183 | 'and then get dependent with command: dart pub global run dart_mars --get'); 184 | print( 185 | 'and then start it with command: dart pub global run dart_mars --serve dev'); 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /lib/helper/GetHelper.dart: -------------------------------------------------------------------------------- 1 | import 'package:process_run/shell.dart'; 2 | 3 | class GetHelper { 4 | static void run() { 5 | var str = 'dart pub get'; 6 | Shell().run(str); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /lib/helper/Helper.dart: -------------------------------------------------------------------------------- 1 | class Helper { 2 | static void run() { 3 | print('Helper'); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /lib/helper/PackageHelper.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:yaml/yaml.dart'; 4 | 5 | class PackageHelper { 6 | static List typeList = ['exe', 'aot', 'jit', 'kernel', 'js']; 7 | 8 | static String getRootPath() { 9 | return Directory.current.path.replaceAll('\\', '/'); 10 | } 11 | 12 | static String getPackageName() { 13 | var file = File(getRootPath() + '/pubspec.yaml'); 14 | 15 | var doc = loadYaml(file.readAsStringSync()); 16 | 17 | return doc['name'].toString(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/helper/RunHelper.dart: -------------------------------------------------------------------------------- 1 | import 'package:process_run/shell.dart'; 2 | import 'PackageHelper.dart'; 3 | 4 | class RunHelper { 5 | static void run(String type) { 6 | var str = 'dart run bin/' + PackageHelper.getPackageName() + '.dart'; 7 | Shell().run(str); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/helper/ServeHelper.dart: -------------------------------------------------------------------------------- 1 | import 'dart:core'; 2 | 3 | import 'package:process_run/shell.dart'; 4 | import 'PackageHelper.dart'; 5 | import './serve/RouteConfigHelper.dart'; 6 | import './serve/DataBaseHelper.dart'; 7 | 8 | class ServeHelper { 9 | static Future run(List arguments) async { 10 | await DataBaseHelper.analyseFile(); 11 | 12 | bool ispass = RouteConfigHelper.analyseFile(); 13 | if (!ispass) { 14 | print('serve has been stop, some mistake has been print above'); 15 | return; 16 | } 17 | 18 | _runServe(arguments); 19 | } 20 | 21 | static void _runServe(List arguments) { 22 | var str = 'dart run bin/' + 23 | PackageHelper.getPackageName() + 24 | '.dart ' + 25 | arguments.join(' '); 26 | 27 | Shell().run(str); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/helper/WelcomeHelper.dart: -------------------------------------------------------------------------------- 1 | class WelcomeHelper { 2 | static void run() { 3 | print('Welcome use dart mars'); 4 | print('For start new project, please type:'); 5 | print('--------------------------------'); 6 | print('dart pub global run dart_mars --create project_name'); 7 | print('cd project_name'); 8 | print('dart pub global run dart_mars --serve'); 9 | print('--------------------------------'); 10 | print('For help, please type:'); 11 | print('--------------------------------'); 12 | print('dart pub global run dart_mars --help'); 13 | print('--------------------------------'); 14 | print('Enjoy'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/helper/serve/DataBaseHelper.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:yaml/yaml.dart'; 4 | 5 | import '../PackageHelper.dart'; 6 | import 'DataFieldHelper.dart'; 7 | import 'package:mysql1/mysql1.dart'; 8 | 9 | class DataBaseHelper { 10 | static Map defaultLengthMap = { 11 | 'varchar': '255', 12 | 'tinyint': '4', 13 | 'int': '11', 14 | 'bigint': '20' 15 | }; 16 | 17 | static Future analyseFile() async { 18 | List> allTableStructLocal = _getTableStructFromLocal(); 19 | 20 | String devYaml = PackageHelper.getRootPath() + '/env/dev.yaml'; 21 | var devMap = loadYaml(File(devYaml).readAsStringSync()); 22 | 23 | await _syncTableField(allTableStructLocal, devMap); 24 | } 25 | 26 | /// 同步本地数据结构到数据库 27 | static Future _syncTableField( 28 | List> allTableStructLocal, dynamic devMap) async { 29 | List sqlList = []; 30 | 31 | MySqlConnection conn = await _getConn(devMap); 32 | 33 | Map> tableStruckDb = 34 | await _getTableStruckFromDb(conn, devMap['dbName'].toString()); 35 | 36 | List> insertTableStructLocal = []; 37 | List> updateTableStructLocal = []; 38 | allTableStructLocal.forEach((tableStructLocal) { 39 | String tableName = tableStructLocal['name'].toString(); 40 | if (tableStruckDb.keys.contains(tableName)) { 41 | updateTableStructLocal.add(tableStructLocal); 42 | } else { 43 | insertTableStructLocal.add(tableStructLocal); 44 | } 45 | }); 46 | 47 | //不存在的表,新建 48 | if (insertTableStructLocal.isNotEmpty) { 49 | insertTableStructLocal.forEach((element) { 50 | sqlList.add(DataFieldHelper.buildSql(element)); 51 | }); 52 | } 53 | 54 | //存在的表,新建字段或者修改字段,新建索引或者修改索引 55 | if (updateTableStructLocal.isNotEmpty) { 56 | Map> fieldStruckDb = 57 | await _getFieldStruckFromDb(conn, devMap['dbName'].toString()); 58 | 59 | updateTableStructLocal.forEach((table) { 60 | (table['fieldList'] as List).forEach((fieldDynamic) { 61 | Map field = Map.from(fieldDynamic); 62 | 63 | String key = 64 | table['name'].toString() + '|' + field['name'].toString(); 65 | 66 | if (!fieldStruckDb.containsKey(key)) { 67 | sqlList.add(_getAddOrModifyFieldSql(table, field, 'ADD')); 68 | } else { 69 | Map fieldDb = fieldStruckDb[key]; 70 | Map fieldLocal = 71 | _getFieldMapFromLocal(table, field); 72 | 73 | bool isSame = fieldDb.toString() == fieldLocal.toString(); 74 | 75 | if (!isSame) { 76 | //print('---------------------'); 77 | //print(fieldDb); 78 | //print(fieldLocal); 79 | 80 | if (fieldDb['COLUMN_KEY'].toString() == 81 | fieldLocal['COLUMN_KEY'].toString()) { 82 | sqlList.add(_getAddOrModifyFieldSql(table, field, 'MODIFY')); 83 | } else { 84 | //删掉已有的 85 | if (fieldDb['COLUMN_KEY'].toString() != '') { 86 | sqlList.add('alter table ' + 87 | table['name'].toString() + 88 | ' drop index ' + 89 | field['name'].toString()); 90 | } 91 | 92 | //增加新的 93 | if (fieldLocal['COLUMN_KEY'].toString() != '') { 94 | String key = ''; 95 | 96 | if ('PRI' == fieldLocal['COLUMN_KEY'].toString()) { 97 | key = 'primary key'; 98 | } 99 | 100 | if ('UNI' == fieldLocal['COLUMN_KEY'].toString()) { 101 | key = 'unique'; 102 | } 103 | 104 | if ('MUL' == fieldLocal['COLUMN_KEY'].toString()) { 105 | key = 'index'; 106 | } 107 | 108 | sqlList.add('alter table ' + 109 | table['name'].toString() + 110 | ' add ' + 111 | key + 112 | ' (' + 113 | field['name'].toString() + 114 | ')'); 115 | } 116 | } 117 | } 118 | } 119 | }); 120 | }); 121 | } 122 | 123 | if (sqlList.isNotEmpty) { 124 | print('database stuck should be modify'); 125 | sqlList.forEach((sql) async { 126 | print(sql); 127 | await conn.query(sql); 128 | }); 129 | } 130 | } 131 | 132 | /// 生成添加或者修改字段SQL语句 133 | static String _getAddOrModifyFieldSql( 134 | Map table, Map field, String optType) { 135 | Map fieldMapFromLocal = 136 | _getFieldMapFromLocal(table, field); 137 | 138 | String sql = 'ALTER TABLE ' + 139 | table['name'].toString() + 140 | ' $optType ' + 141 | field['name'].toString(); 142 | 143 | fieldMapFromLocal.keys.forEach((keyItem) { 144 | sql += _fieldTag( 145 | table['type'].toString(), keyItem, fieldMapFromLocal[keyItem]); 146 | }); 147 | 148 | return sql; 149 | } 150 | 151 | /// 从本地数据读取字段结构 152 | static Map _getFieldMapFromLocal( 153 | Map table, Map field) { 154 | String COLUMN_KEY = ''; 155 | if ('primary key' == field['key'].toString()) COLUMN_KEY = 'PRI'; 156 | if ('unique key' == field['key'].toString()) COLUMN_KEY = 'UNI'; 157 | if ('key' == field['key'].toString()) COLUMN_KEY = 'MUL'; 158 | 159 | String COLUMN_TYPE = ''; 160 | if (field['type'].toString() != 'text') { 161 | COLUMN_TYPE = 162 | field['type'].toString() + '(' + field['length'].toString() + ')'; 163 | } else { 164 | COLUMN_TYPE = field['type'].toString(); 165 | } 166 | 167 | return { 168 | 'TABLE_NAME': table['name'].toString(), 169 | 'COLUMN_NAME': field['name'].toString(), 170 | 'DATA_TYPE': field['type'].toString(), 171 | 'COLUMN_TYPE': COLUMN_TYPE, 172 | 'CHARACTER_SET_NAME': field['character'].toString(), 173 | 'COLLATION_NAME': field['collation'].toString(), 174 | 'IS_NULLABLE': field['nullAble'].toString(), 175 | 'COLUMN_DEFAULT': field['def'].toString(), 176 | 'COLUMN_KEY': COLUMN_KEY, 177 | 'COLUMN_COMMENT': field['comment'].toString(), 178 | }; 179 | } 180 | 181 | /// 从数据库中读取字段结构 182 | static Future>> _getFieldStruckFromDb( 183 | MySqlConnection conn, String dataBaseName) async { 184 | Results results = await conn.query(''' 185 | SELECT 186 | A.TABLE_NAME, 187 | A.COLUMN_NAME, 188 | A.DATA_TYPE, 189 | A.COLUMN_TYPE, 190 | A.CHARACTER_SET_NAME, 191 | A.COLLATION_NAME, 192 | A.IS_NULLABLE, 193 | A.COLUMN_DEFAULT, 194 | A.COLUMN_KEY, 195 | A.COLUMN_COMMENT 196 | FROM INFORMATION_SCHEMA.COLUMNS A 197 | WHERE A.TABLE_SCHEMA='$dataBaseName' 198 | ORDER BY A.TABLE_NAME,A.ORDINAL_POSITION 199 | '''); 200 | 201 | Map> map = {}; 202 | results.forEach((element) { 203 | String key = element.fields['TABLE_NAME'].toString() + 204 | '|' + 205 | element.fields['COLUMN_NAME'].toString(); 206 | map[key] = element.fields; 207 | }); 208 | 209 | return map; 210 | } 211 | 212 | /// 从数据库中读取表结构 213 | static Future>> _getTableStruckFromDb( 214 | MySqlConnection conn, String dataBaseName) async { 215 | Results results = await conn.query(''' 216 | SELECT 217 | A.TABLE_NAME 218 | FROM INFORMATION_SCHEMA.TABLES A 219 | WHERE A.TABLE_SCHEMA='$dataBaseName' 220 | ORDER BY A.TABLE_NAME 221 | '''); 222 | 223 | Map> map = {}; 224 | results.forEach((element) { 225 | String key = element.fields['TABLE_NAME'].toString(); 226 | map[key] = element.fields; 227 | }); 228 | 229 | return map; 230 | } 231 | 232 | /// 获取数据库连接 233 | static Future _getConn(dynamic devMap) async { 234 | var settings = ConnectionSettings( 235 | host: devMap['dbHost'].toString(), 236 | port: int.parse(devMap['dbPort'].toString()), 237 | user: devMap['dbUser'].toString(), 238 | password: devMap['dbPassword'].toString(), 239 | db: devMap['dbName'].toString()); 240 | MySqlConnection conn = await MySqlConnection.connect(settings); 241 | 242 | return conn; 243 | } 244 | 245 | /// 从本地文件读取表结构与字段结构 246 | static List> _getTableStructFromLocal() { 247 | List fileList = []; 248 | String appPath = PackageHelper.getRootPath() + '/lib/extend/model'; 249 | 250 | _allFile(fileList, appPath); 251 | 252 | List> tableStruct = []; 253 | fileList.forEach((fileName) { 254 | var fileContent = File(fileName).readAsStringSync(); 255 | Map tableMap = 256 | _handleTableStructList(fileName, fileContent); 257 | 258 | if (null != tableMap) tableStruct.add(tableMap); 259 | }); 260 | 261 | return tableStruct; 262 | } 263 | 264 | /// 从本地文件读取表结构与字段结构,遍历给定目录的所有文件 265 | static void _allFile(List fileList, String path) { 266 | Directory(path).listSync().forEach((element) { 267 | if (element.path.contains('.')) { 268 | fileList.add(element.path.replaceAll('\\', '/')); 269 | } else { 270 | _allFile(fileList, element.path); 271 | } 272 | }); 273 | } 274 | 275 | /// 从本地文件读取表结构与字段结构,正则匹配表结构与字段结构 276 | static Map _handleTableStructList( 277 | String fileName, String fileContent) { 278 | RegExpMatch regExpMatch = 279 | RegExp(r'@TableMeta.*?\{', multiLine: true, dotAll: true) 280 | .firstMatch(fileContent); 281 | if (null == regExpMatch) return null; 282 | 283 | String tableMetaAndClassName = regExpMatch.group(0).toString().trim(); 284 | 285 | Map tableMap = _getTableMap(tableMetaAndClassName); 286 | tableMap['fieldList'] = []; 287 | 288 | Iterable matchs = 289 | RegExp(r'@FieldMeta.*?;', multiLine: true, dotAll: true) 290 | .allMatches(fileContent); 291 | for (Match m in matchs) { 292 | String fieldMetaAndFieldName = m.group(0).toString(); 293 | Map fieldMap = _getFieldMap(fieldMetaAndFieldName); 294 | if (null != fieldMap) tableMap['fieldList'].add(fieldMap); 295 | } 296 | 297 | return tableMap; 298 | } 299 | 300 | /// 从本地文件读取表结构与字段结构,正则匹配表结构与字段结构-表结构 301 | static Map _getTableMap(String tableMetaAndClassName) { 302 | Map tableMap = {}; 303 | 304 | String tableMeta = RegExp(r'@TableMeta.*\)', multiLine: true, dotAll: true) 305 | .firstMatch(tableMetaAndClassName) 306 | .group(0) 307 | .toString() 308 | .trim(); 309 | String className = tableMetaAndClassName.replaceFirst(tableMeta, '').trim(); 310 | 311 | tableMeta = tableMeta.replaceFirst('@TableMeta(', ''); 312 | tableMeta = tableMeta.substring(0, tableMeta.length - 1); 313 | tableMeta.split(',').forEach((e) { 314 | List ss = e.trim().split(':'); 315 | tableMap[ss[0].trim()] = 316 | ss[1].trim().replaceAll('\'', '').replaceAll('\"', ''); 317 | }); 318 | 319 | className = className 320 | .replaceAll('class', '') 321 | .replaceAll('{', '') 322 | .replaceAll(' ', ''); 323 | if (!tableMap.containsKey('name')) { 324 | tableMap['name'] = _strToUnderLine(className).substring(1); 325 | } 326 | 327 | return tableMap; 328 | } 329 | 330 | /// 从本地文件读取表结构与字段结构,正则匹配表结构与字段结构-字段结构 331 | static Map _getFieldMap(String fieldMetaAndFieldName) { 332 | Map fieldMap = {}; 333 | 334 | String fieldMeta = RegExp(r'@FieldMeta.*\)', multiLine: true, dotAll: true) 335 | .firstMatch(fieldMetaAndFieldName) 336 | .group(0) 337 | .toString() 338 | .trim(); 339 | String fieldName = fieldMetaAndFieldName.replaceFirst(fieldMeta, '').trim(); 340 | 341 | fieldMeta = fieldMeta.replaceFirst('@FieldMeta(', ''); 342 | fieldMeta = fieldMeta.substring(0, fieldMeta.length - 1); 343 | fieldMeta.split(',').forEach((e) { 344 | List ss = e.trim().split(':'); 345 | fieldMap[ss[0].trim()] = 346 | ss[1].trim().replaceAll('\'', '').replaceAll('\"', ''); 347 | }); 348 | 349 | List fieldNameSplit = fieldName.replaceFirst(';', '').split(' '); 350 | 351 | if (fieldMap.containsKey('ignore') && 352 | fieldMap.containsKey('ignore').toString() == 'true') return null; 353 | 354 | if (!fieldMap.containsKey('type')) { 355 | if (fieldNameSplit[0] == 'String') fieldMap['type'] = 'varchar'; 356 | if (fieldNameSplit[0] == 'int') fieldMap['type'] = 'int'; 357 | } 358 | 359 | if (!fieldMap.containsKey('name')) { 360 | fieldMap['name'] = _strToUnderLine(fieldNameSplit[1]); 361 | } 362 | 363 | if (!fieldMap.containsKey('length')) { 364 | fieldMap['length'] = defaultLengthMap[fieldMap['type'].toString()]; 365 | } 366 | 367 | if (!fieldMap.containsKey('comment')) { 368 | fieldMap['comment'] = ''; 369 | } 370 | 371 | if (fieldMap['type'] == 'varchar' || fieldMap['type'] == 'text') { 372 | if (!fieldMap.containsKey('character')) { 373 | fieldMap['character'] = 'utf8mb4'; 374 | } 375 | 376 | if (!fieldMap.containsKey('collation')) { 377 | fieldMap['collation'] = 'utf8mb4_general_ci'; 378 | } 379 | } 380 | 381 | if (!fieldMap.containsKey('nullAble')) { 382 | fieldMap['nullAble'] = 'NO'; 383 | } else { 384 | fieldMap['nullAble'] = fieldMap['nullAble'].toString().toUpperCase(); 385 | } 386 | 387 | return fieldMap; 388 | } 389 | 390 | /// 字符串驼峰转下划线 391 | static String _strToUnderLine(String str) { 392 | List l = []; 393 | for (var i = 0; i < str.length; i++) { 394 | if (str[i] != str[i].toLowerCase()) { 395 | l.add('_'); 396 | } 397 | 398 | l.add(str[i].toLowerCase()); 399 | } 400 | return l.join(); 401 | } 402 | 403 | /// 字段信息 404 | static String _fieldTag(String dataType, String keyItem, dynamic valueItem) { 405 | String sql = ''; 406 | 407 | if ('COLUMN_TYPE' == keyItem) { 408 | sql += ' ' + valueItem.toString(); 409 | } 410 | 411 | if (dataType == 'varchar') { 412 | if ('CHARACTER_SET_NAME' == keyItem) { 413 | sql += ' CHARACTER SET ' + valueItem.toString(); 414 | } 415 | 416 | if ('COLLATION_NAME' == keyItem) { 417 | sql += ' COLLATE ' + valueItem.toString(); 418 | } 419 | } 420 | 421 | if ('IS_NULLABLE' == keyItem) { 422 | if (valueItem.toString() == '' || valueItem.toString() == 'NO') { 423 | sql += ' NOT NULL'; 424 | } else { 425 | sql += ' NULL'; 426 | } 427 | } 428 | 429 | if ('COLUMN_DEFAULT' == keyItem) { 430 | if ('null' == valueItem.toString()) { 431 | sql += ' DEFAULT NULL'; 432 | } else { 433 | sql += ' DEFAULT \'' + valueItem.toString() + '\''; 434 | } 435 | } 436 | 437 | if ('COLUMN_COMMENT' == keyItem) { 438 | sql += ' COMMENT \'' + valueItem.toString() + '\''; 439 | } 440 | 441 | if ('COLUMN_KEY' == keyItem) { 442 | // sql += ' ' + valueItem.toString(); 443 | } 444 | 445 | return sql; 446 | } 447 | } 448 | -------------------------------------------------------------------------------- /lib/helper/serve/DataFieldHelper.dart: -------------------------------------------------------------------------------- 1 | class DataFieldHelper { 2 | static String buildSql(Map map) { 3 | String name = map['name'].toString(); 4 | String engine = 5 | map.containsKey('engine') ? map['engine'].toString() : 'InnoDB'; 6 | String charset = 7 | map.containsKey('charset') ? map['charset'].toString() : 'utf8mb4'; 8 | String comment = 9 | map.containsKey('comment') ? map['comment'].toString() : ''; 10 | 11 | var sb = StringBuffer(); 12 | sb.write('CREATE TABLE IF NOT EXISTS \`$name\` (\n'); 13 | 14 | //循环字段 15 | (map['fieldList'] as List).forEach((element) { 16 | sb.write(_buildField(Map.from(element))); 17 | }); 18 | 19 | //循环索引 20 | (map['fieldList'] as List).forEach((element) { 21 | String key = _buildKey(Map.from(element)); 22 | if (key != '') sb.write(key + ',\n'); 23 | }); 24 | 25 | sb.write(') ENGINE=' + 26 | engine + 27 | ' DEFAULT CHARSET=' + 28 | charset + 29 | ' COLLATE=utf8mb4_general_ci COMMENT=\'' + 30 | comment + 31 | '\''); 32 | 33 | String s = sb.toString(); 34 | int i = s.lastIndexOf('),'); 35 | s = s.replaceRange(i, i + 2, ')'); 36 | 37 | return s; 38 | } 39 | 40 | static String _buildField(Map m) { 41 | String type = m['type'].toString(); 42 | 43 | var sb = StringBuffer(); 44 | sb.write(_pareFieldName(m)); 45 | sb.write(_pareFieldType(m)); 46 | 47 | if ('varchar' == type) { 48 | sb.write(' CHARACTER SET utf8mb4'); 49 | sb.write(' COLLATE utf8mb4_general_ci'); 50 | } 51 | 52 | if (type != 'text') { 53 | sb.write(' NOT NULL'); 54 | } else { 55 | sb.write(' NULL'); 56 | } 57 | 58 | sb.write(_pareFieldDefault(m)); 59 | sb.write(_pareFieldAutoIncrease(m)); 60 | sb.write(_pareFieldComment(m)); 61 | sb.write(',\n'); 62 | 63 | return sb.toString(); 64 | } 65 | 66 | static String _pareFieldName(Map m) { 67 | String name = m['name'].toString(); 68 | return '`' + name + '`'; 69 | } 70 | 71 | static String _pareFieldType(Map m) { 72 | String type = m['type'].toString(); 73 | if ('text' == type) return ' text'; 74 | 75 | String length = 76 | m.containsKey('length') ? m['length'].toString() : _defaultLength(type); 77 | 78 | return ' ' + type + '(' + length + ')'; 79 | } 80 | 81 | static String _defaultLength(String type) { 82 | if (type == 'varchar') return '255'; 83 | if (type == 'tinyint') return '4'; 84 | if (type == 'int') return '11'; 85 | if (type == 'bigint') return '20'; 86 | return ''; 87 | } 88 | 89 | static String _pareFieldDefault(Map m) { 90 | if (!m.containsKey('def')) return ''; 91 | 92 | String type = m['type'].toString(); 93 | 94 | return ' DEFAULT \'' + (type == 'varchar' ? '' : '0') + '\''; 95 | } 96 | 97 | static String _pareFieldAutoIncrease(Map m) { 98 | String autoIncrease = 99 | (m.containsKey('autoIncrease') && m['autoIncrease'] == 'true') 100 | ? ' AUTO_INCREMENT' 101 | : ''; 102 | 103 | return autoIncrease; 104 | } 105 | 106 | static String _pareFieldComment(Map m) { 107 | String comment = m.containsKey('comment') 108 | ? ' COMMENT \'' + m['comment'].toString() + '\'' 109 | : ''; 110 | 111 | return comment; 112 | } 113 | 114 | static String _buildKey(Map m) { 115 | if (!m.containsKey('key') || m['key'].toString() == '') return ''; 116 | 117 | String key = m['key'].toString().toUpperCase(); 118 | String name = m['name'].toString(); 119 | 120 | return key + ' `' + name + '` (`' + name + '`)'; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /lib/helper/serve/RouteConfigHelper.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import '../PackageHelper.dart'; 4 | 5 | class RouteConfigHelper { 6 | // ignore: omit_local_variable_types 7 | static bool analyseFile() { 8 | List fileList = []; 9 | String appPath = PackageHelper.getRootPath() + '/lib/app'; 10 | 11 | _allFile(fileList, appPath); 12 | 13 | List routeStructList = []; 14 | 15 | fileList.forEach((fileName) { 16 | var fileContent = File(fileName).readAsStringSync(); 17 | _handleRouteStructList(fileName, fileContent, routeStructList); 18 | }); 19 | 20 | bool ispass = _checkRouteStruct(routeStructList); 21 | if (ispass) _replaceRouteConfig(routeStructList); 22 | return ispass; 23 | } 24 | 25 | static void _allFile(List fileList, String path) { 26 | Directory(path).listSync().forEach((element) { 27 | if (element.path.contains('.')) { 28 | fileList.add(element.path.replaceAll('\\', '/')); 29 | } else { 30 | _allFile(fileList, element.path); 31 | } 32 | }); 33 | } 34 | 35 | static void _handleRouteStructList( 36 | String fileName, String fileContent, List routeStructList) { 37 | RegExp exp = RegExp(r'@RouteMeta\((.*?)\).*?void\s+(\w+)\(.*?{', 38 | multiLine: true, dotAll: true); 39 | 40 | Iterable matchs = exp.allMatches(fileContent); 41 | 42 | for (Match m in matchs) { 43 | List l = m.group(1).toString().split(','); 44 | String path = l[0].replaceAll('\'', '').replaceAll(' ', ''); 45 | String method = l[1].replaceAll('\'', '').replaceAll(' ', ''); 46 | String functionName = m.group(2).toString(); 47 | 48 | routeStructList.add(RouteStruct(path, method, fileName, functionName)); 49 | } 50 | } 51 | 52 | static bool _checkRouteStruct(List routeStructList) { 53 | bool isPass = true; 54 | Map> map = {}; 55 | 56 | routeStructList.forEach((element) { 57 | if (!map.containsKey(element.path)) map[element.path] = []; 58 | map[element.path].add(element.fileName); 59 | }); 60 | 61 | map.forEach((key, value) { 62 | if (value.length > 1) { 63 | isPass = false; 64 | print('duplicate route path ' + 65 | key + 66 | ' was found, please check it from these files:'); 67 | value.forEach((element) { 68 | print(element); 69 | }); 70 | } 71 | }); 72 | 73 | return isPass; 74 | } 75 | 76 | static void _replaceRouteConfig(List routeStructList) { 77 | var routePath = PackageHelper.getRootPath() + '/lib/config/route.dart'; 78 | File file = File(routePath); 79 | 80 | List fileNameList = []; 81 | routeStructList.forEach((element) { 82 | if (!fileNameList.contains(element.fileName)) { 83 | fileNameList.add(element.fileName); 84 | } 85 | }); 86 | 87 | file.writeAsStringSync(''); 88 | 89 | file.writeAsStringSync('import \'../bootstrap/helper/RouteHelper.dart\';\n', 90 | mode: FileMode.append); 91 | 92 | fileNameList.forEach((element) { 93 | element = element.replaceAll(PackageHelper.getRootPath() + '/lib/', ''); 94 | file.writeAsStringSync(_importLine(element) + '\n', 95 | mode: FileMode.append); 96 | }); 97 | 98 | file.writeAsStringSync('\n', mode: FileMode.append); 99 | 100 | file.writeAsStringSync('/// \n', mode: FileMode.append); 101 | file.writeAsStringSync( 102 | '/// don\'t modify this file yourself, this file content will be replace by DartMars\n', 103 | mode: FileMode.append); 104 | file.writeAsStringSync('/// \n', mode: FileMode.append); 105 | file.writeAsStringSync('/// for more infomation, see doc about Route \n', 106 | mode: FileMode.append); 107 | file.writeAsStringSync('/// \n', mode: FileMode.append); 108 | file.writeAsStringSync( 109 | '/// last replace time ' + DateTime.now().toString() + ' \n', 110 | mode: FileMode.append); 111 | file.writeAsStringSync('/// \n', mode: FileMode.append); 112 | 113 | file.writeAsStringSync('void configRoute(){\n', mode: FileMode.append); 114 | 115 | routeStructList.forEach((element) { 116 | file.writeAsStringSync(' ', mode: FileMode.append); 117 | 118 | file.writeAsStringSync(_routeLine(element) + '\n', mode: FileMode.append); 119 | }); 120 | 121 | file.writeAsStringSync('}', mode: FileMode.append); 122 | 123 | print('route config file has been updated, see ./lib/config/route.dart'); 124 | } 125 | 126 | static String _fileTag(String element) { 127 | element = element.replaceAll(PackageHelper.getRootPath() + '/lib/', ''); 128 | element = element.replaceAll('.dart', ''); 129 | element = element.replaceAll('/', '_'); 130 | return element; 131 | } 132 | 133 | static String _importLine(String element) { 134 | var sb = StringBuffer(); 135 | sb 136 | ..write('import') 137 | ..write(' \'../') 138 | ..write(element) 139 | ..write('\'') 140 | ..write(' as ') 141 | ..write(_fileTag(element)) 142 | ..write(';'); 143 | return sb.toString(); 144 | } 145 | 146 | static String _routeLine(RouteStruct element) { 147 | String tag = _fileTag(element.fileName); 148 | String file = tag.split('_').last; 149 | 150 | var sb = StringBuffer(); 151 | sb 152 | ..write('RouteHelper.add(') 153 | ..write('\'') 154 | ..write(element.method) 155 | ..write('\', \'') 156 | ..write(element.path) 157 | ..write('\', ') 158 | ..write(tag) 159 | ..write('.') 160 | ..write(file) 161 | ..write('.') 162 | ..write(element.functionName) 163 | ..write(');'); 164 | return sb.toString(); 165 | } 166 | } 167 | 168 | class RouteStruct { 169 | String path; 170 | String method; 171 | String fileName; 172 | String functionName; 173 | 174 | RouteStruct(this.path, this.method, this.fileName, this.functionName); 175 | } 176 | -------------------------------------------------------------------------------- /lib/template/Pubspec.dart: -------------------------------------------------------------------------------- 1 | class Pubspec { 2 | static String content = ''' 3 | name: {package} 4 | environment: 5 | sdk: '>=2.10.0 <3.0.0' 6 | dependencies: 7 | yaml: ^3.1.0 8 | mysql1: ^0.19.2 9 | redis: ^1.4.0 10 | mime: ^1.0.0 11 | encrypt: ^5.0.0 12 | '''; 13 | } 14 | -------------------------------------------------------------------------------- /lib/template/app/config/ConfigContext.dart: -------------------------------------------------------------------------------- 1 | class ConfigContext { 2 | static String content = ''' 3 | import '../bootstrap/Context.dart'; 4 | 5 | /// 6 | /// here, you can extended function for Context 7 | /// 8 | /// for more infomation, see doc about Context 9 | /// 10 | void configContext(Context cxt) { 11 | 12 | } 13 | '''; 14 | } 15 | -------------------------------------------------------------------------------- /lib/template/app/config/ConfigDatabase.dart: -------------------------------------------------------------------------------- 1 | class ConfigDatabase { 2 | static String content = ''' 3 | import '../bootstrap/db/DbConfig.dart'; 4 | 5 | /// 6 | /// here, you can accect Database config from env 7 | /// 8 | /// for more infomation, see doc about Database 9 | /// 10 | void configDatabase(String envType, Map env) { 11 | DbConfig.dbHost = env['dbHost'].toString(); 12 | DbConfig.dbPort = int.parse(env['dbPort'].toString()); 13 | DbConfig.dbUser = env['dbUser'].toString(); 14 | DbConfig.dbPassword = env['dbPassword'].toString(); 15 | DbConfig.dbName = env['dbName'].toString(); 16 | } 17 | '''; 18 | } 19 | -------------------------------------------------------------------------------- /lib/template/app/config/ConfigHook.dart: -------------------------------------------------------------------------------- 1 | class ConfigHook { 2 | static String content = ''' 3 | import '../bootstrap/Context.dart'; 4 | 5 | /// 6 | /// here, you can do something before DartMars call controller 7 | /// 8 | /// such as record request info, or verify the request param 9 | /// 10 | /// for more infomation, see doc about Hook 11 | /// 12 | void hookBeforeCall(Context ctx) async {} 13 | 14 | /// 15 | /// here, you can do something after DartMars call controller 16 | /// 17 | /// such as rewrite response content, or remove sensitive information 18 | /// 19 | /// for more infomation, see doc about Hook 20 | /// 21 | void hookAfterCall(Context ctx) async {} 22 | '''; 23 | } 24 | -------------------------------------------------------------------------------- /lib/template/app/config/ConfigLog.dart: -------------------------------------------------------------------------------- 1 | class ConfigLog { 2 | static String content = ''' 3 | import '../bootstrap/helper/LogHelper.dart'; 4 | 5 | /// 6 | /// here, you can set config for Log 7 | /// 8 | /// for more infomation, see doc about Log 9 | /// 10 | void configLog() { 11 | LogHelper.isOutLog = true; 12 | LogHelper.isErrLog = true; 13 | LogHelper.outLogName = 'log_out_{date}.txt'; 14 | LogHelper.errLogName = 'log_err_{date}.txt'; 15 | LogHelper.logForm = 'levelName,time,sequenceNumber,loggerName,message'; 16 | LogHelper.logSeparator = '::'; 17 | } 18 | '''; 19 | } 20 | -------------------------------------------------------------------------------- /lib/template/app/config/ConfigRoute.dart: -------------------------------------------------------------------------------- 1 | class ConfigRoute { 2 | static String content = ''' 3 | import '../bootstrap/helper/RouteHelper.dart'; 4 | import '../app/controller/HomeController.dart' as app_controller_HomeController; 5 | 6 | /// 7 | /// don't modify this file yourself, this file content will be replace by DartMars 8 | /// 9 | /// for more infomation, see doc about Route 10 | /// 11 | /// last replace time {time} 12 | /// 13 | void configRoute() { 14 | RouteHelper.add('GET', '/', app_controller_HomeController.HomeController.index); 15 | RouteHelper.add('GET', '/user', app_controller_HomeController.HomeController.user); 16 | RouteHelper.add('GET', '/city/:cityName', app_controller_HomeController.HomeController.city); 17 | } 18 | '''; 19 | } 20 | -------------------------------------------------------------------------------- /lib/template/app/controller/HomeController.dart: -------------------------------------------------------------------------------- 1 | class HomeController { 2 | static String content = ''' 3 | import 'package:{package}/bootstrap/Context.dart'; 4 | import 'package:{package}/bootstrap/meta/RouteMeta.dart'; 5 | 6 | class HomeController { 7 | @RouteMeta('/', 'GET') 8 | static void index(Context ctx) async { 9 | ctx.html("hello world"); 10 | } 11 | 12 | @RouteMeta('/user', 'GET') 13 | static void user(Context ctx) async { 14 | String name = ctx.getString('name'); 15 | // some other code 16 | ctx.html("hello " + name); 17 | } 18 | 19 | @RouteMeta('/city/:cityName', 'GET') 20 | static void city(Context ctx, String cityName) async { 21 | ctx.html("hello " + cityName); 22 | } 23 | } 24 | '''; 25 | } 26 | -------------------------------------------------------------------------------- /lib/template/bin/Bin.dart: -------------------------------------------------------------------------------- 1 | class Bin { 2 | static String content = ''' 3 | import 'package:{package}/bootstrap/App.dart'; 4 | 5 | main(List arguments) { 6 | App.startHttp(arguments); 7 | } 8 | '''; 9 | } 10 | -------------------------------------------------------------------------------- /lib/template/bootstrap/App.dart: -------------------------------------------------------------------------------- 1 | class App { 2 | static String content = ''' 3 | import 'dart:io'; 4 | import 'Server.dart'; 5 | import 'helper/CommonHelper.dart'; 6 | import 'helper/LogHelper.dart'; 7 | import 'package:yaml/yaml.dart'; 8 | import '../config/log.dart'; 9 | import '../config/route.dart'; 10 | import '../config/database.dart'; 11 | 12 | class App { 13 | static String _className = 'App'; 14 | static String serveDefault = 'prod'; 15 | static int portDefault = 80; 16 | static int portHttpsDefault = 443; 17 | static String envPath = '/env/'; 18 | static List envFieldList = [ 19 | 'dbHost', 20 | 'dbPort', 21 | 'dbUser', 22 | 'dbPassword', 23 | 'dbName' 24 | ]; 25 | 26 | static void startHttp(List arguments) { 27 | configLog(); 28 | LogHelper.init(); 29 | configRoute(); 30 | 31 | try { 32 | Map argMap = _argMap(arguments); 33 | int port = _getPort(argMap); 34 | String serve = _getServe(argMap); 35 | Map env = _getEnv(CommonHelper.rootPath(), serve); 36 | 37 | configDatabase(serve, env); 38 | 39 | _autoConnectDbPeriodic(env); 40 | 41 | Server.http(port, serve, env); 42 | 43 | if (env.containsKey('ssl') && env['ssl'].toString() == 'on') { 44 | int portHttps = _getPortHttps(argMap); 45 | Server.https(portHttps, serve, env); 46 | } 47 | } catch (e, s) { 48 | LogHelper.warning(_className, 49 | 'Error is found when server start , ' + e.toString(), e, s); 50 | } 51 | } 52 | 53 | static String _getServe(Map argMap) { 54 | if (!argMap.containsKey('serve')) return serveDefault; 55 | 56 | String serve = argMap["serve"].toString(); 57 | 58 | if (serve.isEmpty) return serveDefault; 59 | 60 | return serve; 61 | } 62 | 63 | static int _getPort(Map argMap) { 64 | try { 65 | if (argMap.containsKey('port')) 66 | return int.parse(argMap["port"].toString()); 67 | } catch (e) { 68 | throw 'param port must between 0 and 65535, unused by other program'; 69 | } 70 | 71 | return portDefault; 72 | } 73 | 74 | static int _getPortHttps(Map argMap) { 75 | try { 76 | if (argMap.containsKey('portHttps')) 77 | return int.parse(argMap["portHttps"].toString()); 78 | } catch (e) { 79 | throw 'param portHttps must between 0 and 65535, unused by other program'; 80 | } 81 | 82 | return portHttpsDefault; 83 | } 84 | 85 | static Map _getEnv(String path, String serve) { 86 | String filePath = path + envPath + serve + '.yaml'; 87 | 88 | File file = File(filePath); 89 | if (!file.existsSync()) 90 | throw 'could not find env file, the path is : ' + filePath; 91 | 92 | var envContent = loadYaml(file.readAsStringSync()); 93 | Map envMap = Map.from(envContent); 94 | 95 | envFieldList.forEach((fieldName) { 96 | if (!envMap.containsKey(fieldName)) 97 | throw 'could not find param ' + fieldName + ' in env'; 98 | }); 99 | 100 | return envMap; 101 | } 102 | 103 | static Map _argMap(List arguments) { 104 | Map map = Map(); 105 | 106 | for (int i = 0; i < arguments.length; i = i + 2) { 107 | if (!arguments[i].startsWith('--')) 108 | throw 'param start with --, such like --serve, --port'; 109 | String key = arguments[i].replaceAll('--', ''); 110 | String val = i + 1 >= arguments.length ? "" : arguments[i + 1]; 111 | 112 | map[key] = val; 113 | } 114 | 115 | return map; 116 | } 117 | 118 | static void _autoConnectDbPeriodic(Map env) { 119 | int dbConnectPeriodic = 20000; 120 | if (env.containsKey("dbConnectPeriodic")) { 121 | try { 122 | dbConnectPeriodic = int.parse(env["dbConnectPeriodic"].toString()); 123 | } catch (e) {} 124 | } 125 | 126 | Timer.periodic(Duration(seconds: dbConnectPeriodic), (timer) async { 127 | await Db.query("select 1", []); 128 | }); 129 | } 130 | 131 | } 132 | '''; 133 | } 134 | -------------------------------------------------------------------------------- /lib/template/bootstrap/Context.dart: -------------------------------------------------------------------------------- 1 | class Context { 2 | static String content = ''' 3 | import 'dart:async'; 4 | import 'dart:io'; 5 | import 'dart:convert'; 6 | import 'model/UploadFile.dart'; 7 | import 'helper/RequestHelper.dart'; 8 | 9 | class Context { 10 | String serve; 11 | Map env; 12 | 13 | HttpRequest request; 14 | HttpResponse response; 15 | ContentType responseType; 16 | String responseContent; 17 | bool _responseIsClose = false; 18 | 19 | Map header = Map(); 20 | Map query = Map(); 21 | Map body = Map(); 22 | Map session = Map(); 23 | Map cookie = Map(); 24 | Map customize = Map(); 25 | 26 | Context({this.serve, this.env}); 27 | 28 | Future handle(HttpRequest request) async { 29 | this.request = request; 30 | this.response = request.response; 31 | 32 | this.header = RequestHelper.getHeader(request); 33 | this.query = RequestHelper.getQuery(request); 34 | this.body = await RequestHelper.getBody(request); 35 | this.session = await RequestHelper.getSession(request); 36 | } 37 | 38 | UploadFile getUploadFile(String key, {UploadFile def = null, int from = 0}) { 39 | Map all = _getAllParams(from); 40 | 41 | if (all.containsKey(key)) { 42 | try { 43 | return all[key] as UploadFile; 44 | } catch (e) { 45 | return def; 46 | } 47 | } 48 | 49 | return def; 50 | } 51 | 52 | String getString(String key, {String def = "", int from = 0}) { 53 | Map all = _getAllParams(from); 54 | 55 | if (all.containsKey(key)) return all[key].toString(); 56 | return def; 57 | } 58 | 59 | int getInt(String key, {int def = 0, int from = 0}) { 60 | Map all = _getAllParams(from); 61 | 62 | if (all.containsKey(key)) { 63 | try { 64 | return int.parse(all[key].toString()); 65 | } catch (e) {} 66 | } 67 | 68 | return def; 69 | } 70 | 71 | int getPositiveInt(String key, {int def = 0, int from = 0}) { 72 | int i = getInt(key, def: def, from: from); 73 | return i > 0 ? i : def; 74 | } 75 | 76 | int getNegativeInt(String key, {int def = 0, int from = 0}) { 77 | int i = getInt(key, def: def, from: from); 78 | return i < 0 ? i : def; 79 | } 80 | 81 | double getDouble(String key, {double def = 0, int from = 0}) { 82 | Map all = _getAllParams(from); 83 | 84 | if (all.containsKey(key)) { 85 | try { 86 | return double.parse(all[key].toString()); 87 | } catch (e) {} 88 | } 89 | 90 | return def; 91 | } 92 | 93 | double getPositiveDouble(String key, {double def = 0, int from = 0}) { 94 | double i = getDouble(key, def: def, from: from); 95 | return i > 0 ? i : def; 96 | } 97 | 98 | double getNegativeDouble(String key, {double def = 0, int from = 0}) { 99 | double i = getDouble(key, def: def, from: from); 100 | return i < 0 ? i : def; 101 | } 102 | 103 | void html(String raw) { 104 | responseType = ContentType.html; 105 | responseContent = raw; 106 | } 107 | 108 | void text(String raw) { 109 | responseType = ContentType.text; 110 | responseContent = raw; 111 | } 112 | 113 | void json(String raw) { 114 | responseType = ContentType.json; 115 | responseContent = raw; 116 | } 117 | 118 | void binary(String raw) { 119 | responseType = ContentType.binary; 120 | responseContent = raw; 121 | } 122 | 123 | Future writeAndClose() async { 124 | response.headers.contentType = responseType; 125 | response.write(responseContent); 126 | await response.close(); 127 | _responseIsClose = true; 128 | } 129 | 130 | bool responseIsClose() => _responseIsClose; 131 | 132 | void showJson(num code, String msg, dynamic data) { 133 | Map map = {"code": code, "msg": msg, "data": data}; 134 | 135 | json(jsonEncode(map)); 136 | } 137 | 138 | void showSuccess(String msg, dynamic data) { 139 | showJson(200, msg, data); 140 | } 141 | 142 | void showError(String msg) { 143 | showJson(400, msg, {}); 144 | } 145 | 146 | Map _getAllParams(int from) { 147 | Map allParams = Map(); 148 | if (from == 0 || from == 1) allParams.addAll(this.header); 149 | if (from == 0 || from == 2) allParams.addAll(this.query); 150 | if (from == 0 || from == 3) allParams.addAll(this.body); 151 | if (from == 0 || from == 4) allParams.addAll(this.session); 152 | if (from == 0 || from == 5) allParams.addAll(this.cookie); 153 | if (from == 0 || from == 6) allParams.addAll(this.customize); 154 | return allParams; 155 | } 156 | } 157 | '''; 158 | } 159 | -------------------------------------------------------------------------------- /lib/template/bootstrap/Server.dart: -------------------------------------------------------------------------------- 1 | class Server { 2 | static String content = ''' 3 | import 'dart:convert'; 4 | import 'dart:io'; 5 | 6 | import 'helper/RouteHelper.dart'; 7 | import 'helper/LogHelper.dart'; 8 | import 'helper/CommonHelper.dart'; 9 | import 'Context.dart'; 10 | import '../config/context.dart'; 11 | 12 | class Server { 13 | static String _className = 'Server'; 14 | 15 | static void http(int port, String serve, Map env) { 16 | HttpServer.bind('0.0.0.0', port).then((httpServer) async { 17 | await _http(httpServer, port, serve, env); 18 | }); 19 | } 20 | 21 | static void https(int port, String serve, Map env) { 22 | SecurityContext securityContext = SecurityContext(); 23 | securityContext.useCertificateChain( 24 | CommonHelper.rootPath() + '/' + env['sslCertificate'].toString()); 25 | securityContext.usePrivateKey( 26 | CommonHelper.rootPath() + '/' + env['sslCertificateKey'].toString()); 27 | 28 | HttpServer.bindSecure('0.0.0.0', port, securityContext) 29 | .then((httpServer) async { 30 | await _http(httpServer, port, serve, env); 31 | }); 32 | } 33 | 34 | static Future _http(HttpServer httpServer, int port, String serve, 35 | Map env) async { 36 | httpServer.autoCompress = true; 37 | 38 | LogHelper.info( 39 | _className, 'Http Server has start, port=' + port.toString()); 40 | LogHelper.info(_className, 'Env type is ' + serve); 41 | LogHelper.info( 42 | _className, 43 | 'Open browser and vist http://127.0.0.1:' + 44 | port.toString() + 45 | ' , you can see some info'); 46 | 47 | httpServer.listen((HttpRequest request) async { 48 | await _onData(request, serve, env); 49 | }, onError: _onError, onDone: _onDone); 50 | } 51 | 52 | static Future _onData( 53 | HttpRequest request, String serve, Map env) async { 54 | LogHelper.info(_className, '------------------'); 55 | LogHelper.info(_className, 'Http Request start'); 56 | LogHelper.info(_className, 'request.uri.path = ' + request.uri.path); 57 | 58 | bool isFile = request.uri.path.contains('.'); 59 | bool isExists = false; 60 | File file; 61 | if (isFile) { 62 | file = File(CommonHelper.rootPath() + '/public' + request.uri.path); 63 | isExists = file.existsSync(); 64 | } 65 | 66 | if (isFile && isExists) { 67 | await _handleFile(request, file); 68 | } else { 69 | Context ctx = Context(serve: serve, env: env); 70 | configContext(ctx); 71 | await ctx.handle(request); 72 | 73 | LogHelper.info(_className, 'ctx.query = ' + jsonEncode(ctx.query)); 74 | LogHelper.info(_className, 'ctx.body = ' + jsonEncode(ctx.body)); 75 | 76 | await RouteHelper.handle(ctx); 77 | LogHelper.info( 78 | _className, 'ctx.responseContent = ' + ctx.responseContent); 79 | } 80 | 81 | LogHelper.info(_className, 'Http Request end'); 82 | } 83 | 84 | static void _onError(Object e, StackTrace s) => 85 | LogHelper.warning(_className, 'onError', e, s); 86 | 87 | static void _onDone() => LogHelper.info(_className, '_onDone'); 88 | 89 | static Future _handleFile(HttpRequest request, File file) async { 90 | try { 91 | request.response.statusCode = HttpStatus.ok; 92 | request.response.headers.contentType = _ContentType(request); 93 | await request.response.addStream(file.openRead()); 94 | } catch (e) { 95 | request.response.statusCode = HttpStatus.internalServerError; 96 | } 97 | 98 | await request.response.close(); 99 | } 100 | 101 | static _ContentType(HttpRequest request) { 102 | List arr = request.uri.path.split('.'); 103 | String suffix = arr.last.toUpperCase(); 104 | ContentType contentType = ContentType.text; 105 | 106 | switch (suffix) { 107 | case 'HTML': 108 | contentType = ContentType.html; 109 | break; 110 | case 'CSS': 111 | contentType = ContentType('text', 'css'); 112 | break; 113 | case 'JS': 114 | contentType = ContentType('text', 'javascript'); 115 | break; 116 | case 'JSON': 117 | contentType = ContentType.json; 118 | break; 119 | case 'PNG': 120 | contentType = ContentType('image', 'png'); 121 | break; 122 | default: 123 | } 124 | 125 | return contentType; 126 | } 127 | } 128 | '''; 129 | } 130 | -------------------------------------------------------------------------------- /lib/template/bootstrap/crypto/AES.dart: -------------------------------------------------------------------------------- 1 | class AES { 2 | static String content = ''' 3 | import 'dart:convert'; 4 | import 'package:encrypt/encrypt.dart' as encryptAlias; 5 | 6 | /// 7 | /// String plainText = 'this is a test from aes'; 8 | /// Key key = Key.fromUtf8('my 32 length key................'); 9 | /// IV iv = IV.fromLength(16); 10 | /// 11 | /// AESHelper aesHelper = AESHelper(key: key, iv: iv); 12 | /// 13 | /// print(plainText); 14 | /// String encrypted = aesHelper.encrypt(plainText); 15 | /// print(encrypted); 16 | /// 17 | /// String decrypted = aesHelper.decrypt(encrypted); 18 | /// print(decrypted); 19 | /// 20 | class AES { 21 | encryptAlias.Encrypter _encrypter; 22 | encryptAlias.IV _iv; 23 | 24 | AES( 25 | {encryptAlias.Key key, 26 | encryptAlias.IV iv, 27 | encryptAlias.AESMode mode = encryptAlias.AESMode.sic, 28 | String padding = 'PKCS7'}) { 29 | _iv = iv; 30 | _encrypter = 31 | encryptAlias.Encrypter(encryptAlias.AES(key, mode: mode, padding: padding)); 32 | } 33 | 34 | String encrypt(String plainText) { 35 | encryptAlias.Encrypted encrypted = _encrypter.encrypt(plainText, iv: _iv); 36 | 37 | return base64.encode(encrypted.bytes); 38 | } 39 | 40 | String decrypt(String encrypted) { 41 | List decodeList = base64.decode(encrypted); 42 | 43 | return _encrypter.decrypt(encryptAlias.Encrypted(decodeList), iv: _iv); 44 | } 45 | } 46 | '''; 47 | } 48 | -------------------------------------------------------------------------------- /lib/template/bootstrap/crypto/RSA.dart: -------------------------------------------------------------------------------- 1 | class RSA { 2 | static String content = ''' 3 | import 'dart:convert'; 4 | import 'dart:math'; 5 | import 'package:encrypt/encrypt.dart' as encryptAlias; 6 | import 'package:pointycastle/asymmetric/api.dart'; 7 | 8 | class RSA { 9 | int _encryptStep; 10 | int _decryptStep; 11 | encryptAlias.Encrypter _encrypter; 12 | 13 | RSA({String publicKey, String privateKey, int length}) { 14 | _encryptStep = length ~/ 8 - 11; 15 | _decryptStep = length ~/ 8; 16 | 17 | RSAPublicKey rsaPublicKey = 18 | encryptAlias.RSAKeyParser().parse(publicKey) as RSAPublicKey; 19 | 20 | RSAPrivateKey rsaPrivateKey = 21 | encryptAlias.RSAKeyParser().parse(privateKey) as RSAPrivateKey; 22 | 23 | _encrypter = encryptAlias.Encrypter( 24 | encryptAlias.RSA(publicKey: rsaPublicKey, privateKey: rsaPrivateKey)); 25 | } 26 | 27 | String encrypt(String plainText) { 28 | List encryptList = []; 29 | for (int i = 0; i < plainText.codeUnits.length; i = i + _encryptStep) { 30 | List encryptItem = plainText.codeUnits 31 | .sublist(i, min(i + _encryptStep, plainText.codeUnits.length)); 32 | 33 | encryptAlias.Encrypted encrypted = _encrypter.encryptBytes(encryptItem); 34 | 35 | encryptList.addAll(encrypted.bytes); 36 | } 37 | 38 | return base64.encode(encryptList); 39 | } 40 | 41 | String decrypt(String encrypted) { 42 | List decodeList = base64.decode(encrypted); 43 | List decryptList = []; 44 | for (int i = 0; i < decodeList.length; i = i + _decryptStep) { 45 | List decryptItem = 46 | decodeList.sublist(i, min(i + _decryptStep, decodeList.length)); 47 | 48 | List s = _encrypter.decryptBytes(encryptAlias.Encrypted(decryptItem)); 49 | 50 | decryptList.addAll(s); 51 | } 52 | return String.fromCharCodes(decryptList); 53 | } 54 | } 55 | '''; 56 | } 57 | -------------------------------------------------------------------------------- /lib/template/bootstrap/crypto/Sha1WithRSA.dart: -------------------------------------------------------------------------------- 1 | class Sha1WithRSA { 2 | static String content = ''' 3 | import 'ShaRsaHelper.dart'; 4 | 5 | class Sha1WithRSA { 6 | static final String _algorithmName = 'SHA-1/RSA'; 7 | 8 | static String generateSignature(String message, String privateKey) => 9 | ShaRsaHelper(_algorithmName).generateSignature(message, privateKey); 10 | 11 | static bool verifySignature( 12 | String message, String publicKey, String generate) => 13 | ShaRsaHelper(_algorithmName) 14 | .verifySignature(message, publicKey, generate); 15 | } 16 | '''; 17 | } 18 | -------------------------------------------------------------------------------- /lib/template/bootstrap/crypto/Sha256WithRSA.dart: -------------------------------------------------------------------------------- 1 | class Sha256WithRSA { 2 | static String content = ''' 3 | import 'ShaRsaHelper.dart'; 4 | 5 | class Sha256WithRSA { 6 | static final String _algorithmName = 'SHA-256/RSA'; 7 | 8 | static String generateSignature(String message, String privateKey) => 9 | ShaRsaHelper(_algorithmName).generateSignature(message, privateKey); 10 | 11 | static bool verifySignature( 12 | String message, String publicKey, String generate) => 13 | ShaRsaHelper(_algorithmName) 14 | .verifySignature(message, publicKey, generate); 15 | } 16 | '''; 17 | } 18 | -------------------------------------------------------------------------------- /lib/template/bootstrap/crypto/ShaRsaHelper.dart: -------------------------------------------------------------------------------- 1 | class ShaRsaHelper { 2 | static String content = ''' 3 | import 'dart:convert'; 4 | import 'dart:typed_data'; 5 | import 'package:encrypt/encrypt.dart'; 6 | import 'package:pointycastle/asymmetric/api.dart'; 7 | import 'package:pointycastle/pointycastle.dart' as pointycastle; 8 | 9 | class ShaRsaHelper { 10 | final String _algorithmName; 11 | 12 | ShaRsaHelper(this._algorithmName); 13 | 14 | String generateSignature(String message, String privateKey) { 15 | RSAPrivateKey rsaPrivateKey = 16 | RSAKeyParser().parse(privateKey) as RSAPrivateKey; 17 | 18 | var privParams = pointycastle.ParametersWithRandom( 19 | pointycastle.PrivateKeyParameter(rsaPrivateKey), null); 20 | 21 | var privSigner = pointycastle.Signer(_algorithmName); 22 | privSigner.reset(); 23 | privSigner.init(true, privParams); 24 | 25 | RSASignature signature = 26 | privSigner.generateSignature(Uint8List.fromList(message.codeUnits)); 27 | String dey = base64.encode(signature.bytes); 28 | 29 | return dey; 30 | } 31 | 32 | bool verifySignature(String message, String publicKey, String generate) { 33 | RSAPublicKey rsaPublicKey = RSAKeyParser().parse(publicKey) as RSAPublicKey; 34 | 35 | var pubParams = pointycastle.ParametersWithRandom( 36 | pointycastle.PublicKeyParameter(rsaPublicKey), null); 37 | 38 | var pubSigner = pointycastle.Signer(_algorithmName); 39 | pubSigner.reset(); 40 | pubSigner.init(false, pubParams); 41 | 42 | RSASignature rsaSignature = RSASignature(base64.decode(generate)); 43 | bool b = pubSigner.verifySignature( 44 | Uint8List.fromList(message.codeUnits), rsaSignature); 45 | 46 | return b; 47 | } 48 | } 49 | '''; 50 | } 51 | -------------------------------------------------------------------------------- /lib/template/bootstrap/db/Db.dart: -------------------------------------------------------------------------------- 1 | class Db { 2 | static String content = ''' 3 | import 'package:mysql1/mysql1.dart'; 4 | import 'DbConnection.dart'; 5 | import 'DbSqlBuilder.dart'; 6 | import 'DbColumn.dart'; 7 | 8 | class Db { 9 | Map condition = {}; 10 | 11 | Db(String tableName) { 12 | this.condition["table"] = tableName; 13 | } 14 | 15 | Future insert(Map data) async { 16 | this.condition["data"] = data; 17 | 18 | List values = []; 19 | String sql = DbSqlBuilder.insert(this.condition, values); 20 | 21 | int id = await DbConnection.insert(sql, values); 22 | 23 | return id; 24 | } 25 | 26 | Future>> select() async { 27 | List values = []; 28 | String sql = DbSqlBuilder.select(this.condition, values); 29 | 30 | List> list = await DbConnection.select(sql, values); 31 | 32 | return list; 33 | } 34 | 35 | Future> find() async { 36 | List> list = await this.select(); 37 | 38 | if (list.length > 0) { 39 | return list[0]; 40 | } else { 41 | return null; 42 | } 43 | } 44 | 45 | Future update(Map data) async { 46 | this.condition["set"] = data; 47 | 48 | List values = []; 49 | String sql = DbSqlBuilder.update(this.condition, values); 50 | 51 | int count = await DbConnection.update(sql, values); 52 | 53 | return count; 54 | } 55 | 56 | Future delete() async { 57 | List values = []; 58 | String sql = DbSqlBuilder.delete(this.condition, values); 59 | 60 | int count = await DbConnection.update(sql, values); 61 | 62 | return count; 63 | } 64 | 65 | static Future query(String sql, [List values]) async { 66 | return await DbConnection.doQuery(sql, values); 67 | } 68 | 69 | Future count(String field) async { 70 | String fieldName = "count(" + field + ")"; 71 | 72 | num n = await _n(fieldName); 73 | 74 | return int.parse(n.toString()); 75 | } 76 | 77 | Future sum(String field) async { 78 | String fieldName = "sum(" + field + ")"; 79 | 80 | num n = await _n(fieldName); 81 | 82 | return double.parse(n.toString()); 83 | } 84 | 85 | Future avg(String field) async { 86 | String fieldName = "avg(" + field + ")"; 87 | 88 | num n = await _n(fieldName); 89 | 90 | return double.parse(n.toString()); 91 | } 92 | 93 | Future min(String field) async { 94 | String fieldName = "min(" + field + ")"; 95 | return await _n(fieldName); 96 | } 97 | 98 | Future max(String field) async { 99 | String fieldName = "max(" + field + ")"; 100 | return await _n(fieldName); 101 | } 102 | 103 | Future _n(String fieldName) async { 104 | this.condition["field"] = fieldName; 105 | List> list = await this.select(); 106 | if (!list[0].containsKey(fieldName)) return 0; 107 | return list[0][fieldName]; 108 | } 109 | 110 | static void startTrans() async { 111 | await DbConnection.startTrans(); 112 | } 113 | 114 | static void commit() async { 115 | await DbConnection.commit(); 116 | } 117 | 118 | static void rollback() async { 119 | await DbConnection.rollback(); 120 | } 121 | 122 | Db alias(String s) { 123 | this.condition["alias"] = s; 124 | return this; 125 | } 126 | 127 | Db where(List where) { 128 | this.condition["where"] = where; 129 | return this; 130 | } 131 | 132 | Db having(List having) { 133 | this.condition["having"] = having; 134 | return this; 135 | } 136 | 137 | Db field(String s) { 138 | this.condition["field"] = s; 139 | return this; 140 | } 141 | 142 | Db lock(bool s) { 143 | this.condition["lock"] = s; 144 | return this; 145 | } 146 | 147 | Db page(int pageNum, int pageSize) { 148 | this.limit((pageNum - 1) * pageSize, pageSize); 149 | return this; 150 | } 151 | 152 | Db limit(int offset, int count) { 153 | this.condition["limit"] = [offset, count]; 154 | return this; 155 | } 156 | 157 | Db join(String name, String onCondition, String type) { 158 | if (!this.condition.containsKey("join")) { 159 | this.condition["join"] = []; 160 | } 161 | this.condition["join"].add([name, onCondition, type]); 162 | return this; 163 | } 164 | 165 | Db innerJoin(String name, String onCondition) { 166 | return join(name, onCondition, "inner"); 167 | } 168 | 169 | Db leftJoin(String name, String onCondition) { 170 | return join(name, onCondition, "left"); 171 | } 172 | 173 | Db rightJoin(String name, String onCondition) { 174 | return join(name, onCondition, "right"); 175 | } 176 | 177 | Db group(String s) { 178 | this.condition["group"] = s; 179 | return this; 180 | } 181 | 182 | Db distinct(bool s) { 183 | this.condition["distinct"] = s; 184 | return this; 185 | } 186 | 187 | Db extra(String s) { 188 | this.condition["extra"] = s; 189 | return this; 190 | } 191 | 192 | Db order(String s) { 193 | this.condition["order"] = s; 194 | return this; 195 | } 196 | 197 | Db union(String s) { 198 | this.condition["union"] = s; 199 | return this; 200 | } 201 | 202 | Db using(String s) { 203 | this.condition["using"] = s; 204 | return this; 205 | } 206 | 207 | Db comment(String s) { 208 | this.condition["comment"] = s; 209 | return this; 210 | } 211 | 212 | Db force(String s) { 213 | this.condition["force"] = s; 214 | return this; 215 | } 216 | } 217 | '''; 218 | } 219 | -------------------------------------------------------------------------------- /lib/template/bootstrap/db/DbColumn.dart: -------------------------------------------------------------------------------- 1 | class DbColumn { 2 | static String content = ''' 3 | import '../helper/ConvertHelper.dart'; 4 | 5 | class DbColumn { 6 | String fieldName; 7 | String optName; 8 | dynamic fieldVal; 9 | 10 | DbColumn(this.fieldName, this.optName, this.fieldVal); 11 | 12 | DbColumn.fieldToUnderLine(String fieldName, String optName, dynamic fieldVal) { 13 | this.fieldName = ConvertHelper.strToUnderLine(fieldName); 14 | this.optName = optName; 15 | this.fieldVal = fieldVal; 16 | } 17 | } 18 | 19 | '''; 20 | } 21 | -------------------------------------------------------------------------------- /lib/template/bootstrap/db/DbConfig.dart: -------------------------------------------------------------------------------- 1 | class DbConfig { 2 | static String content = ''' 3 | class DbConfig { 4 | static String dbHost; 5 | static int dbPort; 6 | static String dbUser; 7 | static String dbPassword; 8 | static String dbName; 9 | } 10 | '''; 11 | } 12 | -------------------------------------------------------------------------------- /lib/template/bootstrap/db/DbConnection.dart: -------------------------------------------------------------------------------- 1 | class DbConnection { 2 | static String content = ''' 3 | import 'dart:core'; 4 | import 'dart:async'; 5 | import 'package:mysql1/mysql1.dart'; 6 | import 'DbConfig.dart'; 7 | 8 | class DbConnection { 9 | DbConnection._privateConstructor(); 10 | 11 | static final DbConnection _instance = DbConnection._privateConstructor(); 12 | factory DbConnection() => _instance; 13 | 14 | static MySqlConnection conn; 15 | 16 | static Future getConn() async { 17 | if (null == conn) { 18 | var settings = new ConnectionSettings( 19 | host: DbConfig.dbHost, 20 | port: DbConfig.dbPort, 21 | user: DbConfig.dbUser, 22 | password: DbConfig.dbPassword, 23 | db: DbConfig.dbName); 24 | conn = await MySqlConnection.connect(settings); 25 | } 26 | 27 | return conn; 28 | } 29 | 30 | static Future insert(String sql, List values) async { 31 | Results result = await doQuery(sql, values); 32 | 33 | return result.insertId; 34 | } 35 | 36 | static Future>> select( 37 | String sql, List values) async { 38 | Results result = await doQuery(sql, values); 39 | 40 | List> list = []; 41 | result.forEach((element) { 42 | Map fields = element.fields; 43 | fields.forEach((key, value) { 44 | if (value is Blob) { 45 | fields[key] = value.toString(); 46 | } 47 | }); 48 | 49 | list.add(fields); 50 | }); 51 | 52 | return list; 53 | } 54 | 55 | static Future update(String sql, List values) async { 56 | Results result = await doQuery(sql, values); 57 | 58 | return result.affectedRows; 59 | } 60 | 61 | static Future doQuery(String sql, [List values]) async { 62 | var conn = await getConn(); 63 | 64 | Results result = await conn.query(sql, values); 65 | 66 | return result; 67 | } 68 | 69 | static void startTrans() async { 70 | await doQuery("start transaction", []); 71 | } 72 | 73 | static void commit() async { 74 | await doQuery("commit", []); 75 | } 76 | 77 | static void rollback() async { 78 | await doQuery("rollback", []); 79 | } 80 | } 81 | '''; 82 | } 83 | -------------------------------------------------------------------------------- /lib/template/bootstrap/db/DbRaw.dart: -------------------------------------------------------------------------------- 1 | class DbRaw { 2 | static String content = ''' 3 | class DbRaw { 4 | String raw; 5 | 6 | DbRaw(this.raw); 7 | } 8 | '''; 9 | } 10 | -------------------------------------------------------------------------------- /lib/template/bootstrap/db/DbSqlBuilder.dart: -------------------------------------------------------------------------------- 1 | class DbSqlBuilder { 2 | static String content = ''' 3 | import 'DbColumn.dart'; 4 | import 'DbRaw.dart'; 5 | 6 | class DbSqlBuilder { 7 | static String selectSql = 8 | 'SELECT%DISTINCT%%EXTRA% %FIELD% FROM %TABLE%%ALIAS%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%UNION%%ORDER%%LIMIT%%LOCK%%COMMENT%'; 9 | static String insertSql = 10 | '%INSERT%%EXTRA% INTO %TABLE% (%FIELD%) VALUES (%DATA%)%COMMENT%'; 11 | static String insertAllSql = 12 | '%INSERT%%EXTRA% INTO %TABLE% (%FIELD%) %DATA%%COMMENT%'; 13 | static String updateSql = 14 | 'UPDATE%EXTRA% %TABLE% SET %SET%%JOIN%%WHERE%%ORDER%%LIMIT%%LOCK%%COMMENT%'; 15 | static String deleteSql = 16 | 'DELETE%EXTRA% FROM %TABLE%%USING%%JOIN%%WHERE%%ORDER%%LIMIT%%LOCK%%COMMENT%'; 17 | 18 | static String insert(Map options, List values) { 19 | Map data = {}; 20 | try { 21 | data = options["data"] as Map; 22 | } catch (e) { 23 | throw 'data for insert is not map'; 24 | } 25 | 26 | List keys = []; 27 | List vals = []; 28 | data.forEach((key, value) { 29 | keys.add(key); 30 | vals.add(value); 31 | }); 32 | 33 | options["field"] = keys.join(","); 34 | options["data"] = vals; 35 | 36 | var sql = insertSql; 37 | 38 | sql = sql.replaceFirst('%INSERT%', 'INSERT'); 39 | sql = sql.replaceFirst('%EXTRA%', _parseExtra(options)); 40 | sql = sql.replaceFirst('%TABLE%', _parseTable(options)); 41 | sql = sql.replaceFirst('%FIELD%', _parseField(options)); 42 | sql = sql.replaceFirst('%DATA%', _parseData(options, values)); 43 | sql = sql.replaceFirst('%COMMENT%', _parseComment(options)); 44 | 45 | return sql; 46 | } 47 | 48 | static String select(Map options, List values) { 49 | var sql = selectSql; 50 | 51 | sql = sql.replaceFirst('%TABLE%', _parseTable(options)); 52 | sql = sql.replaceFirst('%ALIAS%', _parseAlias(options)); 53 | sql = sql.replaceFirst('%DISTINCT%', _parseDistinct(options)); 54 | sql = sql.replaceFirst('%EXTRA%', _parseExtra(options)); 55 | sql = sql.replaceFirst('%FIELD%', _parseField(options)); 56 | sql = sql.replaceFirst('%JOIN%', _parseJoin(options)); 57 | sql = sql.replaceFirst('%WHERE%', _parseWhere(options, values)); 58 | sql = sql.replaceFirst('%GROUP%', _parseGroup(options)); 59 | sql = sql.replaceFirst('%HAVING%', _parseHaving(options, values)); 60 | sql = sql.replaceFirst('%ORDER%', _parseOrder(options)); 61 | sql = sql.replaceFirst('%LIMIT%', _parseLimit(options, values)); 62 | sql = sql.replaceFirst('%UNION%', _parseUnion(options)); 63 | sql = sql.replaceFirst('%LOCK%', _parseLock(options)); 64 | sql = sql.replaceFirst('%COMMENT%', _parseComment(options)); 65 | sql = sql.replaceFirst('%FORCE%', _parseForce(options)); 66 | 67 | return sql; 68 | } 69 | 70 | static String update(Map options, List values) { 71 | String sql = updateSql; 72 | 73 | sql = sql.replaceFirst('%EXTRA%', _parseExtra(options)); 74 | sql = sql.replaceFirst('%TABLE%', _parseTable(options)); 75 | sql = sql.replaceFirst('%SET%', _parseSet(options, values)); 76 | sql = sql.replaceFirst('%JOIN%', _parseJoin(options)); 77 | sql = sql.replaceFirst('%WHERE%', _parseWhere(options, values)); 78 | sql = sql.replaceFirst('%ORDER%', _parseOrder(options)); 79 | sql = sql.replaceFirst('%LIMIT%', _parseLimit(options, values)); 80 | sql = sql.replaceFirst('%LOCK%', _parseLock(options)); 81 | sql = sql.replaceFirst('%COMMENT%', _parseComment(options)); 82 | 83 | return sql; 84 | } 85 | 86 | static String delete(Map options, List values) { 87 | var sql = deleteSql; 88 | 89 | sql = sql.replaceFirst('%TABLE%', _parseTable(options)); 90 | sql = sql.replaceFirst('%USING%', _parseUsing(options)); 91 | sql = sql.replaceFirst('%EXTRA%', _parseExtra(options)); 92 | sql = sql.replaceFirst('%FIELD%', _parseField(options)); 93 | sql = sql.replaceFirst('%JOIN%', _parseJoin(options)); 94 | sql = sql.replaceFirst('%WHERE%', _parseWhere(options, values)); 95 | sql = sql.replaceFirst('%HAVING%', _parseHaving(options, values)); 96 | sql = sql.replaceFirst('%ORDER%', _parseOrder(options)); 97 | sql = sql.replaceFirst('%LIMIT%', _parseLimit(options, values)); 98 | sql = sql.replaceFirst('%UNION%', _parseUnion(options)); 99 | sql = sql.replaceFirst('%LOCK%', _parseLock(options)); 100 | sql = sql.replaceFirst('%COMMENT%', _parseComment(options)); 101 | sql = sql.replaceFirst('%FORCE%', _parseForce(options)); 102 | 103 | return sql; 104 | } 105 | 106 | static String _parseData(Map options, List values) { 107 | if (!options.containsKey("data")) return ""; 108 | 109 | List data = []; 110 | try { 111 | data = options["data"] as List; 112 | } catch (e) { 113 | throw 'data for parseData is not list'; 114 | } 115 | 116 | values.addAll(data); 117 | return data.map((e) => "?").join(","); 118 | } 119 | 120 | static String _parseSet(Map options, List values) { 121 | if (!options.containsKey("set")) return ""; 122 | 123 | List list = []; 124 | Map map = Map.from(options["set"]); 125 | 126 | map.forEach((key, value) { 127 | if (value.runtimeType == DbRaw) { 128 | list.add(key + "=" + (value as DbRaw).raw); 129 | } else { 130 | list.add(key + "=?"); 131 | values.add(value); 132 | } 133 | }); 134 | 135 | return list.join(","); 136 | } 137 | 138 | static String _parseTable(Map options) { 139 | if (!options.containsKey("table")) return ""; 140 | 141 | return options['table'].toString(); 142 | } 143 | 144 | static String _parseDistinct(Map options) { 145 | if (!options.containsKey("distinct")) return ""; 146 | 147 | bool distinct = false; 148 | try { 149 | distinct = options["distinct"] as bool; 150 | } catch (e) { 151 | throw 'distinct for parseDistinct is not bool'; 152 | } 153 | 154 | return distinct ? " Distinct" : ""; 155 | } 156 | 157 | static String _parseExtra(Map options) { 158 | if (!options.containsKey("extra")) return ""; 159 | 160 | return ""; 161 | } 162 | 163 | static String _parseField(Map options) { 164 | if (!options.containsKey("field")) return "*"; 165 | 166 | return options["field"].toString(); 167 | } 168 | 169 | static String _parseAlias(Map options) { 170 | if (!options.containsKey("alias")) return ""; 171 | 172 | return " " + options["alias"].toString(); 173 | } 174 | 175 | static String _parseJoin(Map options) { 176 | if (!options.containsKey("join")) return ""; 177 | 178 | List> list = []; 179 | try { 180 | list = (options["join"] as List) 181 | .map((e) => e as List) 182 | .toList(); 183 | } catch (e) { 184 | throw 'list for parseJoin is not List> , it is ' + 185 | options["join"].runtimeType.toString(); 186 | } 187 | 188 | return list 189 | .map((e) { 190 | return " " + e[2].toUpperCase() + " JOIN " + e[0] + " ON " + e[1]; 191 | }) 192 | .toList() 193 | .join(); 194 | } 195 | 196 | static String _parseWhere(Map options, List values) { 197 | if (!options.containsKey("where")) return ""; 198 | 199 | List list = []; 200 | try { 201 | list = options["where"] as List; 202 | } catch (e) { 203 | throw 'list for parseWhere is not List'; 204 | } 205 | 206 | if (list.length == 0) return ""; 207 | 208 | List l = list.map((e) => _parseWhereItem(e, values)).toList(); 209 | 210 | return " WHERE " + l.join(" AND "); 211 | } 212 | 213 | static String _parseWhereItem(DbColumn item, List values) { 214 | String optName = item.optName.toUpperCase(); 215 | 216 | if (['=', '!=', '<>', '>', '<', '>=', '<='].contains(optName)) { 217 | values.add(item.fieldVal); 218 | return item.fieldName + ' ' + optName + ' ' + '?'; 219 | } 220 | 221 | if (['IN', 'NOT IN'].contains(optName)) { 222 | List inValue = item.fieldVal; 223 | 224 | if (inValue.length == 0) 225 | return item.fieldName + ' ' + optName + ' (\\'\\')'; 226 | 227 | values.addAll(inValue); 228 | 229 | String s = inValue.map((e) => '?').toList().join(','); 230 | s = '(' + s + ')'; 231 | 232 | return item.fieldName + ' ' + optName + ' ' + s; 233 | } 234 | 235 | if (['BETWEEN', 'NOT BETWEEN'].contains(optName)) { 236 | List inValue = item.fieldVal; 237 | values.addAll(inValue); 238 | 239 | String s = inValue.map((e) => '?').toList().join(' AND '); 240 | String res = item.fieldName + ' ' + optName + ' ' + s; 241 | 242 | //如果是字符串比较,增加长度限制 243 | if (inValue[0].runtimeType.toString() == "String" || 244 | inValue[1].runtimeType.toString() == "String") { 245 | List lengList = inValue.map((e) => e.toString().length).toList(); 246 | values.addAll(lengList); 247 | 248 | String s1 = ' AND length(' + 249 | item.fieldName + 250 | ') >= ? AND length(' + 251 | item.fieldName + 252 | ') <= ?'; 253 | 254 | res = res + s1; 255 | } 256 | 257 | return res; 258 | } 259 | 260 | if (['LIKE', 'NOT LIKE'].contains(optName)) { 261 | String s = item.fieldVal.toString(); 262 | 263 | List l = []; 264 | for (int i = 0; i < s.length; i++) { 265 | if (s[i] != '%') l.add(s[i]); 266 | } 267 | String value = l.join(); 268 | values.add(value); 269 | 270 | s = s.replaceAll(value, '?'); 271 | s = 'concat(' + s.split('').join(',').replaceAll("%", "'%'") + ')'; 272 | 273 | return item.fieldName + ' ' + optName + ' ' + s; 274 | } 275 | 276 | if ('EXP' == optName) { 277 | String s = item.fieldVal.toString(); 278 | return item.fieldName + s; 279 | } 280 | 281 | return ""; 282 | } 283 | 284 | static String _parseGroup(Map options) { 285 | if (!options.containsKey("group")) return ""; 286 | 287 | return " GROUP BY " + options["group"].toString(); 288 | } 289 | 290 | static String _parseHaving(Map options, List values) { 291 | if (!options.containsKey("having")) return ""; 292 | 293 | List list = []; 294 | try { 295 | list = options["having"] as List; 296 | } catch (e) { 297 | throw 'list for parseHaving is not List'; 298 | } 299 | 300 | if (list.length == 0) return ""; 301 | 302 | List l = list.map((e) => _parseWhereItem(e, values)).toList(); 303 | 304 | return " HAVING " + l.join(" AND "); 305 | } 306 | 307 | static String _parseOrder(Map options) { 308 | if (!options.containsKey("order")) return ""; 309 | 310 | return " ORDER BY " + options["order"].toString(); 311 | } 312 | 313 | static String _parseLimit(Map options, List values) { 314 | if (!options.containsKey("limit")) return ""; 315 | 316 | values.addAll(options["limit"]); 317 | 318 | return " LIMIT ?,?"; 319 | } 320 | 321 | static String _parseUnion(Map options) { 322 | if (!options.containsKey("union")) return ""; 323 | 324 | return ""; 325 | } 326 | 327 | static String _parseLock(Map options) { 328 | if (!options.containsKey("lock")) return ""; 329 | 330 | bool lock = false; 331 | try { 332 | lock = options["lock"] as bool; 333 | } catch (e) { 334 | throw 'lock for parseLock is not bool'; 335 | } 336 | 337 | return lock ? " FOR UPDATE" : ""; 338 | } 339 | 340 | static String _parseUsing(Map options) { 341 | if (!options.containsKey("using")) return ""; 342 | 343 | return ""; 344 | } 345 | 346 | static String _parseComment(Map options) { 347 | if (!options.containsKey("comment")) return ""; 348 | 349 | return " COMMENT " + options["comment"].toString(); 350 | } 351 | 352 | static String _parseForce(Map options) { 353 | if (!options.containsKey("force")) return ""; 354 | 355 | return " FORCE INDEX " + options["force"].toString(); 356 | } 357 | } 358 | '''; 359 | } 360 | -------------------------------------------------------------------------------- /lib/template/bootstrap/helper/CommonHelper.dart: -------------------------------------------------------------------------------- 1 | class CommonHelper { 2 | static String content = ''' 3 | import 'dart:io'; 4 | 5 | class CommonHelper { 6 | static String rootPath(){ 7 | List arr = _pathArr(); 8 | return arr.getRange(0, arr.length - 2).join('/'); 9 | } 10 | 11 | static String scriptName() { 12 | String scriptName = _pathArr().last.toLowerCase(); 13 | return scriptName; 14 | } 15 | 16 | static List _pathArr(){ 17 | List arr = Platform.script.toFilePath().replaceAll('\\\\', '/').split('/'); 18 | return arr; 19 | } 20 | } 21 | '''; 22 | } 23 | -------------------------------------------------------------------------------- /lib/template/bootstrap/helper/ConvertHelper.dart: -------------------------------------------------------------------------------- 1 | class ConvertHelper { 2 | static String content = ''' 3 | class ConvertHelper { 4 | static String strToHump(String str) { 5 | List a = str.split("_"); 6 | 7 | String b = 8 | a.map((e) => e[0].toUpperCase() + e.substring(1)).toList().join(); 9 | 10 | String c = b[0].toLowerCase() + b.substring(1); 11 | 12 | return c; 13 | } 14 | 15 | static String strToUnderLine(String str) { 16 | List l = []; 17 | for (var i = 0; i < str.length; i++) { 18 | if (str[i] != str[i].toLowerCase()) { 19 | l.add("_"); 20 | } 21 | 22 | l.add(str[i].toLowerCase()); 23 | } 24 | return l.join(); 25 | } 26 | 27 | static Map keyToHump(Map map) { 28 | Map newMap = Map(); 29 | 30 | map.forEach((key, value) { 31 | newMap[strToHump(key)] = value; 32 | }); 33 | 34 | return newMap; 35 | } 36 | 37 | static Map keyToUnderLine(Map map) { 38 | Map newMap = Map(); 39 | 40 | map.forEach((key, value) { 41 | if (null != value) { 42 | newMap[strToUnderLine(key)] = value; 43 | } 44 | }); 45 | 46 | return newMap; 47 | } 48 | 49 | static String fieldType(String type) { 50 | if ("tinyint" == type) return "int"; 51 | if ("int" == type) return "int"; 52 | if ("bigint" == type) return "int"; 53 | if ("varchar" == type) return "String"; 54 | if ("float" == type) return "double"; 55 | if ("double" == type) return "double"; 56 | return "unknow" + type; 57 | } 58 | } 59 | 60 | '''; 61 | } 62 | -------------------------------------------------------------------------------- /lib/template/bootstrap/helper/ListHelper.dart: -------------------------------------------------------------------------------- 1 | class ListHelper { 2 | static String content = ''' 3 | class ListHelper { 4 | static List merge(List a, List b) { 5 | List c = []; 6 | c.addAll(a); 7 | c.addAll(b); 8 | return c; 9 | } 10 | 11 | static List unique(List c) { 12 | Set temp = Set(); 13 | temp.addAll(c); 14 | return temp.map((e) => e.toString()).toList(); 15 | } 16 | 17 | // in a, not in b 18 | static List diff(List a, List b) { 19 | List c = []; 20 | 21 | a.forEach((element) { 22 | if (!b.contains(element)) { 23 | c.add(element); 24 | } 25 | }); 26 | 27 | return c; 28 | } 29 | } 30 | '''; 31 | } 32 | -------------------------------------------------------------------------------- /lib/template/bootstrap/helper/LogHelper.dart: -------------------------------------------------------------------------------- 1 | class LogHelper { 2 | static String content = ''' 3 | import 'dart:io'; 4 | import 'CommonHelper.dart'; 5 | import 'package:logging/logging.dart'; 6 | 7 | class LogHelper { 8 | static bool isOutLog; 9 | static bool isErrLog; 10 | static String outLogName; 11 | static String errLogName; 12 | static String logSeparator; 13 | static String logForm; 14 | 15 | static void init() { 16 | String scriptName = CommonHelper.scriptName(); 17 | 18 | Logger.root.level = Level.INFO; 19 | Logger.root.onRecord.listen((LogRecord rec) { 20 | List l = logForm.split(',').map((e) => _text(e, rec)).toList(); 21 | 22 | String content = l.join(logSeparator); 23 | if (scriptName.contains('.dart')) print(content); 24 | 25 | if (rec.level.value >= Level.WARNING.value && isErrLog) 26 | _log(content, errLogName); 27 | if (rec.level.value < Level.WARNING.value && isOutLog) 28 | _log(content, outLogName); 29 | }); 30 | } 31 | 32 | static String _text(String name, LogRecord rec) { 33 | if (name == 'levelName') return rec.level.name; 34 | if (name == 'time') return rec.time.toString(); 35 | if (name == 'sequenceNumber') return rec.sequenceNumber.toString(); 36 | if (name == 'loggerName') return rec.loggerName; 37 | if (name == 'message') return rec.message; 38 | 39 | return ''; 40 | } 41 | 42 | static void info(String loggerName, Object message) => 43 | Logger(loggerName).info(message); 44 | 45 | static void warning(String loggerName, Object message, 46 | [Object error, StackTrace stackTrace]) => 47 | Logger(loggerName).warning(message, error, stackTrace); 48 | 49 | static void _log(String text, String fileName) { 50 | String date = 51 | DateTime.now().toString().substring(0, 9 + 1).replaceAll('-', ''); 52 | 53 | fileName = fileName.replaceAll('{date}', date); 54 | 55 | File file = File(CommonHelper.rootPath() + '/log/' + fileName); 56 | if (!file.existsSync()) file.createSync(); 57 | file.writeAsStringSync(text + '\\n', mode: FileMode.append); 58 | } 59 | } 60 | '''; 61 | } 62 | -------------------------------------------------------------------------------- /lib/template/bootstrap/helper/PrintHelper.dart: -------------------------------------------------------------------------------- 1 | class PrintHelper { 2 | static String content = ''' 3 | class PrintHelper { 4 | static void p(String text) { 5 | print(DateTime.now().toString() + ' ' + text); 6 | } 7 | 8 | static void t(String text) { 9 | print(text); 10 | } 11 | } 12 | '''; 13 | } 14 | -------------------------------------------------------------------------------- /lib/template/bootstrap/helper/RequestHelper.dart: -------------------------------------------------------------------------------- 1 | class RequestHelper { 2 | static String content = ''' 3 | import 'dart:async'; 4 | import 'dart:convert'; 5 | import 'dart:io'; 6 | import '../model/FormData.dart'; 7 | import '../model/UploadFile.dart'; 8 | import 'package:mime/mime.dart'; 9 | 10 | class RequestHelper { 11 | static Map getHeader(HttpRequest request) { 12 | Map map = Map(); 13 | request.headers.forEach((name, values) { 14 | map[name] = values.join(","); 15 | }); 16 | 17 | return map; 18 | } 19 | 20 | static Map getQuery(HttpRequest request) { 21 | return Map.from( 22 | jsonDecode(jsonEncode(request.uri.queryParameters))); 23 | } 24 | 25 | static Map getSession(HttpRequest request) { 26 | Map map = Map(); 27 | 28 | request.session.forEach((key, value) { 29 | map[key.toString()] = value.toString(); 30 | }); 31 | 32 | return map; 33 | } 34 | 35 | static Future> getBody(HttpRequest request) async { 36 | Map map = Map(); 37 | if (null == request.headers.contentType) return map; 38 | 39 | String primaryType = request.headers.contentType.primaryType; 40 | String subType = request.headers.contentType.subType; 41 | String contentType = 42 | request.headers.contentType.toString().split(';').first.toLowerCase(); 43 | 44 | if ("application" == primaryType) { 45 | BytesBuilder bytesBuilder = await request.fold(new BytesBuilder(), 46 | (BytesBuilder builder, List data) => builder..add(data)); 47 | 48 | String bodyStr = utf8.decode(bytesBuilder.takeBytes()); 49 | 50 | if ("x-www-form-urlencoded" == subType) { 51 | map = Uri.parse("?" + bodyStr).queryParameters; 52 | } 53 | 54 | if ("json" == subType) { 55 | try { 56 | map = Map.from(jsonDecode(bodyStr)); 57 | } catch (e) {} 58 | } 59 | } else if ("multipart/form-data" == contentType) { 60 | map = await _asFormData(request); 61 | } else { 62 | print("contentType=" + contentType); 63 | } 64 | 65 | return map; 66 | } 67 | 68 | static Future> _asFormData(HttpRequest request) async { 69 | String boundary = request.headers.contentType.parameters['boundary']; 70 | 71 | var values = await MimeMultipartTransformer(boundary) 72 | .bind(request) 73 | .map( 74 | (MimeMultipart part) => FormData.parse(part, defaultEncoding: utf8)) 75 | .map((multipart) async { 76 | return [_multipartName(multipart), await _multipartData(multipart)]; 77 | }).toList(); 78 | 79 | var parts = await Future.wait(values); 80 | var map = {}; 81 | for (var part in parts) { 82 | map[part[0] as String] = part[1]; 83 | } 84 | 85 | return map; 86 | } 87 | 88 | static String _multipartName(FormData multipart) => 89 | multipart.contentDisposition.parameters['name']; 90 | 91 | static dynamic _multipartData(FormData multipart) async { 92 | dynamic data; 93 | if (multipart.isText) { 94 | var buffer = await multipart.fold( 95 | StringBuffer(), (b, s) => b..write(s)); 96 | data = buffer.toString(); 97 | } else { 98 | var buffer = await multipart.fold( 99 | BytesBuilder(), (b, d) => b..add(d as List)); 100 | data = buffer.takeBytes(); 101 | } 102 | 103 | var filename = multipart.contentDisposition.parameters['filename']; 104 | if (filename != null) { 105 | data = UploadFile(multipart.contentType, filename, data); 106 | } 107 | 108 | return data; 109 | } 110 | } 111 | '''; 112 | } 113 | -------------------------------------------------------------------------------- /lib/template/bootstrap/helper/RouteHelper.dart: -------------------------------------------------------------------------------- 1 | class RouteHelper { 2 | static String content = ''' 3 | import '../Context.dart'; 4 | import '../../config/hook.dart'; 5 | 6 | class RouteItem { 7 | String routeMethod; 8 | String routePath; 9 | Function call; 10 | 11 | RouteItem(this.routeMethod, this.routePath, this.call); 12 | } 13 | 14 | class RouteHelper { 15 | static List list = []; 16 | 17 | RouteHelper(String routePath, Function call) { 18 | add("*", routePath, call); 19 | } 20 | 21 | static get(String routePath, Function call) { 22 | add("GET", routePath, call); 23 | } 24 | 25 | static post(String routePath, Function call) { 26 | add("POST", routePath, call); 27 | } 28 | 29 | static put(String routePath, Function call) { 30 | add("PUT", routePath, call); 31 | } 32 | 33 | static delete(String routePath, Function call) { 34 | add("DELETE", routePath, call); 35 | } 36 | 37 | static add(String method, String routePath, Function call) { 38 | list.add(RouteItem(method, routePath, call)); 39 | } 40 | 41 | static bool _matchMethod(String routeMethod, String requestMethod) { 42 | return routeMethod.split('|').contains(requestMethod) || "*" == routeMethod; 43 | } 44 | 45 | static bool _matchPath( 46 | String routePath, String requestPath, List matchParams) { 47 | if (!routePath.contains(':')) { 48 | return routePath == requestPath; 49 | } else { 50 | return matchParams.length != 0; 51 | } 52 | } 53 | 54 | static List _getMatchParams(String routePath, String requestPath) { 55 | List list = []; 56 | if (!routePath.contains(':')) return list; 57 | 58 | routePath = routePath.replaceAll(RegExp(':\\\\w+'), '(\\\\w+)'); 59 | 60 | RegExpMatch regExpMatch = RegExp(routePath).firstMatch(requestPath); 61 | 62 | if (null != regExpMatch) { 63 | for (int i = 1; i <= regExpMatch.groupCount; i++) { 64 | list.add(regExpMatch.group(i)); 65 | } 66 | } 67 | 68 | return list; 69 | } 70 | 71 | static handle(Context ctx) async { 72 | bool notMatch = true; 73 | 74 | for (RouteItem item in RouteHelper.list) { 75 | List matchParams = 76 | _getMatchParams(item.routePath, ctx.request.uri.path); 77 | 78 | if (_matchMethod(item.routeMethod, ctx.request.method) && 79 | _matchPath(item.routePath, ctx.request.uri.path, matchParams)) { 80 | notMatch = false; 81 | 82 | if (!ctx.responseIsClose()) await hookBeforeCall(ctx); 83 | 84 | if (!ctx.responseIsClose()) { 85 | List args = []; 86 | args.add(ctx); 87 | args.addAll(matchParams); 88 | await Function.apply(item.call, args); 89 | } 90 | 91 | if (!ctx.responseIsClose()) await hookAfterCall(ctx); 92 | 93 | if (!ctx.responseIsClose()) await ctx.writeAndClose(); 94 | 95 | break; 96 | } 97 | } 98 | 99 | if (notMatch) { 100 | ctx.html("NOT FOUND"); 101 | await ctx.writeAndClose(); 102 | } 103 | } 104 | } 105 | '''; 106 | } 107 | -------------------------------------------------------------------------------- /lib/template/bootstrap/helper/TransHelper.dart: -------------------------------------------------------------------------------- 1 | class TransHelper { 2 | static String content = ''' 3 | import '../Context.dart'; 4 | import '../db/Db.dart'; 5 | import '../helper/LogHelper.dart'; 6 | 7 | class TransHelper { 8 | static Future unit({Function tryFunc, Function catchFunc}) async { 9 | try { 10 | await Db.startTrans(); 11 | await tryFunc(); 12 | await Db.commit(); 13 | } catch (e, s) { 14 | await Db.rollback(); 15 | await catchFunc(e, s); 16 | } 17 | } 18 | 19 | static Future simple(Context ctx, Function tryFunc) async { 20 | await unit( 21 | tryFunc: tryFunc, 22 | catchFunc: (e, s) { 23 | LogHelper.warning('TransHelper', e.toString(), e, s); 24 | ctx.showError(e.toString()); 25 | }, 26 | ); 27 | } 28 | } 29 | '''; 30 | } 31 | -------------------------------------------------------------------------------- /lib/template/bootstrap/helper/VerifyHelper.dart: -------------------------------------------------------------------------------- 1 | class VerifyHelper { 2 | static String content = ''' 3 | class VerifyHelper { 4 | /// Retrun true if [s] is empty, otherwise false. 5 | static bool empty(String s) { 6 | if (null == s) return true; 7 | return "" == s; 8 | } 9 | 10 | /// Retrun true if [s] is not empty, otherwise false. 11 | static bool notEmpty(String s) { 12 | return !empty(s); 13 | } 14 | 15 | /// Retrun true if [n] = 0, otherwise false. 16 | /// 17 | /// [n] accept double and int 18 | static bool zero(num n) { 19 | if (null == n) return true; 20 | return 0 == n; 21 | } 22 | 23 | /// Retrun true if [n] != 0, otherwise false. 24 | /// 25 | /// [n] accept double and int 26 | static bool notZero(num n) { 27 | return !zero(n); 28 | } 29 | 30 | /// Retrun true if [n] > 0, otherwise false. 31 | /// 32 | /// [n] accept double and int 33 | static bool positive(num n) { 34 | return n > 0; 35 | } 36 | 37 | /// Retrun true if [n] > 0, otherwise false. 38 | /// 39 | /// [n] only accept int 40 | static bool positiveInt(int n) { 41 | return positive(n); 42 | } 43 | 44 | /// Retrun true if [n] > 0, otherwise false. 45 | /// 46 | /// [n] only accept double 47 | static bool positiveDouble(double n) { 48 | return positive(n); 49 | } 50 | 51 | /// Retrun true if [n] <= 0, otherwise false. 52 | /// 53 | /// [n] accept double and int 54 | static bool notPositive(num n) { 55 | return !positive(n); 56 | } 57 | 58 | /// Retrun true if [n] <= 0, otherwise false. 59 | /// 60 | /// [n] only accept int 61 | static bool notPositiveInt(int n) { 62 | return notPositive(n); 63 | } 64 | 65 | /// Retrun true if [n] <= 0, otherwise false. 66 | /// 67 | /// [n] only accept double 68 | static bool notPositiveDouble(double n) { 69 | return notPositive(n); 70 | } 71 | 72 | /// Retrun true if [n] < 0, otherwise false. 73 | /// 74 | /// [n] accept double and int 75 | static bool negative(num n) { 76 | return n < 0; 77 | } 78 | 79 | /// Retrun true if [n] < 0, otherwise false. 80 | /// 81 | /// [n] only accept int 82 | static bool negativeInt(int n) { 83 | return negative(n); 84 | } 85 | 86 | /// Retrun true if [n] < 0, otherwise false. 87 | /// 88 | /// [n] only accept double 89 | static bool negativeDouble(double n) { 90 | return negative(n); 91 | } 92 | 93 | /// Retrun true if [n] >= 0, otherwise false. 94 | /// 95 | /// [n] accept double and int 96 | static bool notNegative(num n) { 97 | return !negative(n); 98 | } 99 | 100 | /// Retrun true if [n] >= 0, otherwise false. 101 | /// 102 | /// [n] only accept int 103 | static bool notNegativeInt(int n) { 104 | return notNegative(n); 105 | } 106 | 107 | /// Retrun true if [n] >= 0, otherwise false. 108 | /// 109 | /// [n] only accept double 110 | static bool notNegativeDouble(double n) { 111 | return notNegative(n); 112 | } 113 | 114 | /// Retrun true if the length of [s] between [min] and [max], otherwise false. 115 | /// 116 | /// [min] min value 117 | /// 118 | /// [max] max value 119 | static bool lengthBetween(String s, int min, int max) { 120 | return s.length >= min && s.length <= max; 121 | } 122 | 123 | /// Retrun true if the length of [s] not between [min] and [max], otherwise false. 124 | /// 125 | /// [min] min value 126 | /// 127 | /// [max] max value 128 | static bool lengthNotBetween(String s, int min, int max) { 129 | return !lengthBetween(s, min, max); 130 | } 131 | 132 | /// Retrun true if the length of [s] equal to [length], otherwise false. 133 | /// 134 | /// [length] length value 135 | static bool lengthEq(String s, int length) { 136 | return s.length == length; 137 | } 138 | 139 | /// Retrun true if the length of [s] not equal to [length], otherwise false. 140 | /// 141 | /// [length] length value 142 | static bool lengthNotEq(String s, int length) { 143 | return !lengthEq(s, length); 144 | } 145 | 146 | /// Retrun true if the value of [i] between [min] and [max], otherwise false. 147 | /// 148 | /// [min] min value 149 | /// 150 | /// [max] max value 151 | static bool valueBetween(int i, int min, int max) { 152 | return i >= min && i <= max; 153 | } 154 | 155 | /// Retrun true if the value of [i] not between [min] and [max], otherwise false. 156 | /// 157 | /// [min] min value 158 | /// 159 | /// [max] max value 160 | static bool valueNotBetween(int i, int min, int max) { 161 | return !valueBetween(i, min, max); 162 | } 163 | 164 | /// Retrun true if the length of [i] equal to [value], otherwise false. 165 | /// 166 | /// [value] value 167 | static bool valueEq(int s, int value) { 168 | return s == value; 169 | } 170 | 171 | /// Retrun true if the length of [i] not equal to [value], otherwise false. 172 | /// 173 | /// [value] value 174 | static bool valueNotEq(int s, int value) { 175 | return !valueEq(s, value); 176 | } 177 | 178 | /// Retrun true if [s] is email, otherwise false. 179 | static bool email(String s) { 180 | return true; 181 | } 182 | 183 | /// Retrun true if [s] is not email, otherwise false. 184 | static bool notEmail(String s) { 185 | return !email(s); 186 | } 187 | 188 | /// Retrun true if [s] is chinese mobile, otherwise false. 189 | /// 190 | /// China Mobile:134 135 136 137 138 139 147 148 150 151 152 157 158 159 172 178 182 183 184 187 188 195 198 191 | /// 192 | /// China Unicom:130 131 132 145 146 155 156 166 167 171 175 176 185 186 196 193 | /// 194 | /// China Telecom:133 149 153 173 174 177 180 181 189 191 193 199 195 | /// 196 | /// Virtual Network Operator: 162 165 167 170 171 197 | /// 198 | /// start with 13:(0-9)(134 135 136 137 138 139 130 131 132 133) 199 | /// 200 | /// start with 14:(5-9)(147 148 145 146 149) 201 | /// 202 | /// start with 15:(0-3|5-9)(150 151 152 157 158 159 155 156 153) 203 | /// 204 | /// start with 16:(6-7)(166 167) 205 | /// 206 | /// start with 17:(1-8)(172 178 171 175 176 173 174 177) 207 | /// 208 | /// start with 18:(0-9)(182 183 184 187 188 185 186 180 181 189) 209 | /// 210 | /// start with 19:(1|3|5|6|8|9)(195 198 196 191 193 199) 211 | /// 212 | /// @see {https://www.qqzeng.com/article/phone.html} 213 | static bool chsMobile(String s) { 214 | String regex = 215 | "((13[0-9])|(14[5-9])|(15([0-3]|[5-9]))|(16[6-7])|(17[1-8])|(18[0-9])|(19[1|3|5|6|8|9]))\\d{8}"; 216 | RegExp exp = new RegExp(regex); 217 | 218 | return exp.hasMatch(s); 219 | } 220 | 221 | /// Retrun true if [s] is not chinese mobile, otherwise false. 222 | static bool notChsMobile(String s) { 223 | return !chsMobile(s); 224 | } 225 | 226 | /// Retrun true if [s] is chinese IdCard, otherwise false. 227 | static bool chsIdCard(String s) { 228 | bool isMatch = RegExp(r"\d{17}[\d|x|X]|\d{15}").hasMatch(s); 229 | 230 | if (isMatch && s.length == 18) { 231 | List idCardWi = [7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2]; 232 | List idCardY = [1,0,10,9,8,7,6,5,4,3,2]; 233 | 234 | int idCardWiSum = 0; 235 | for (var i = 0; i < 17; i++) { 236 | idCardWiSum += int.parse(s[i]) * idCardWi[i]; 237 | } 238 | 239 | int idCardMod = idCardWiSum % 11; 240 | int idCardLast = idCardY[idCardMod]; 241 | 242 | isMatch = (idCardLast == 10 && (s[17] == 'X' || s[17] == 'x')) || 243 | (idCardLast != 10 && (s[17] == idCardLast.toString())); 244 | } 245 | 246 | return isMatch; 247 | } 248 | 249 | /// Retrun true if [s] is not chinese IdCard, otherwise false. 250 | static bool notChsIdCard(String s) { 251 | return !chsIdCard(s); 252 | } 253 | 254 | /// Retrun true if [s] char is letter, otherwise false. 255 | static bool alpha(String s) { 256 | return !RegExp(r"[^a-zA-Z]+").hasMatch(s); 257 | } 258 | 259 | /// Retrun true if [s] char is not letter, otherwise false. 260 | static bool notAlpha(String s) { 261 | return !alpha(s); 262 | } 263 | 264 | /// Retrun true if [s] char is letter,number, otherwise false. 265 | static bool alphaNum(String s) { 266 | return !RegExp(r"[^a-zA-Z0-9]+").hasMatch(s); 267 | } 268 | 269 | /// Retrun true if [s] char is not letter,number, otherwise false. 270 | static bool notAlphaNum(String s) { 271 | return !alphaNum(s); 272 | } 273 | 274 | /// Retrun true if [s] char is letter,number,-,_, otherwise false. 275 | static bool alphaNumDash(String s) { 276 | return !RegExp(r"[^a-zA-Z0-9\\-\\_]+").hasMatch(s); 277 | } 278 | 279 | /// Retrun true if [s] char is not letter,number,-,_, otherwise false. 280 | static bool notAlphaNumDash(String s) { 281 | return !alphaNumDash(s); 282 | } 283 | 284 | /// Retrun true if [s] char is chinese text, otherwise false. 285 | static bool chs(String s) { 286 | return !RegExp(r"[^\\u4e00-\\u9fa5]+").hasMatch(s); 287 | } 288 | 289 | /// Retrun true if [s] char is not chinese text, otherwise false. 290 | static bool notChs(String s) { 291 | return !chs(s); 292 | } 293 | 294 | /// Retrun true if [s] char is chinese text,letter, otherwise false. 295 | static bool chsAlpha(String s) { 296 | return !RegExp(r"[^a-zA-Z\\u4e00-\\u9fa5]+").hasMatch(s); 297 | } 298 | 299 | /// Retrun true if [s] char is not chinese text,letter, otherwise false. 300 | static bool notChsAlpha(String s) { 301 | return !chsAlpha(s); 302 | } 303 | 304 | /// Retrun true if [s] char is chinese text,letter,number, otherwise false. 305 | static bool chsAlphaNum(String s) { 306 | return !RegExp(r"[^a-zA-Z0-9\\u4e00-\\u9fa5]+").hasMatch(s); 307 | } 308 | 309 | /// Retrun true if [s] char is not chinese text,letter,number, otherwise false. 310 | static bool notChsAlphaNum(String s) { 311 | return !chsAlphaNum(s); 312 | } 313 | 314 | /// Retrun true if [s] char is chinese text,letter,number,-,_, otherwise false. 315 | static bool chsAlphaNumDash(String s) { 316 | return !RegExp(r"[^a-zA-Z0-9\\-\\_\\u4e00-\\u9fa5]+").hasMatch(s); 317 | } 318 | 319 | /// Retrun true if [s] char is not chinese text,letter,number,-,_, otherwise false. 320 | static bool notChsAlphaNumDash(String s) { 321 | return !chsAlphaNumDash(s); 322 | } 323 | } 324 | '''; 325 | } 326 | -------------------------------------------------------------------------------- /lib/template/bootstrap/meta/FieldMeta.dart: -------------------------------------------------------------------------------- 1 | class FieldMeta { 2 | static String content = ''' 3 | class FieldMeta { 4 | final String name; 5 | final String type; 6 | final String length; 7 | final String def; 8 | final String key; 9 | final String autoIncrease; 10 | final String comment; 11 | 12 | const FieldMeta( 13 | {this.name, 14 | this.type, 15 | this.length, 16 | this.def, 17 | this.key, 18 | this.autoIncrease, 19 | this.comment}); 20 | } 21 | '''; 22 | } 23 | -------------------------------------------------------------------------------- /lib/template/bootstrap/meta/RouteMeta.dart: -------------------------------------------------------------------------------- 1 | class RouteMeta { 2 | static String content = ''' 3 | class RouteMeta { 4 | final String path; 5 | final String method; 6 | 7 | const RouteMeta(this.path, this.method); 8 | } 9 | '''; 10 | } 11 | -------------------------------------------------------------------------------- /lib/template/bootstrap/meta/TableMeta.dart: -------------------------------------------------------------------------------- 1 | class TableMeta { 2 | static String content = ''' 3 | class TableMeta { 4 | final String comment; 5 | final String engine; 6 | final String charset; 7 | 8 | const TableMeta({this.comment, this.engine, this.charset}); 9 | } 10 | '''; 11 | } 12 | -------------------------------------------------------------------------------- /lib/template/bootstrap/model/FormData.dart: -------------------------------------------------------------------------------- 1 | class FormData { 2 | static String content = ''' 3 | import 'dart:async'; 4 | import 'dart:convert'; 5 | import 'dart:io'; 6 | 7 | import 'package:mime/mime.dart'; 8 | 9 | class FormData extends Stream { 10 | /// The parsed `Content-Type` header value. 11 | /// 12 | /// `null` if not present. 13 | final ContentType contentType; 14 | 15 | /// The parsed `Content-Disposition` header value. 16 | /// 17 | /// This field is always present. Use this to extract e.g. name (form field 18 | /// name) and filename (client provided name of uploaded file) parameters. 19 | final HeaderValue contentDisposition; 20 | 21 | /// The parsed `Content-Transfer-Encoding` header value. 22 | /// 23 | /// This field is used to determine how to decode the data. Returns `null` 24 | /// if not present. 25 | final HeaderValue contentTransferEncoding; 26 | 27 | /// Whether the data is decoded as [String]. 28 | final bool isText; 29 | 30 | /// Whether the data is raw bytes. 31 | bool get isBinary => !isText; 32 | 33 | /// The values which indicate that no incoding was performed. 34 | /// 35 | /// https://www.w3.org/Protocols/rfc1341/5_Content-Transfer-Encoding.html 36 | static const _transparentEncodings = ['7bit', '8bit', 'binary']; 37 | 38 | /// Parse a [MimeMultipart] and return a [FormData]. 39 | /// 40 | /// If the `Content-Disposition` header is missing or invalid, an 41 | /// [HttpException] is thrown. 42 | /// 43 | /// If the [MimeMultipart] is identified as text, and the `Content-Type` 44 | /// header is missing, the data is decoded using [defaultEncoding]. See more 45 | /// information in the 46 | /// [HTML5 spec](http://dev.w3.org/html5/spec-preview/ 47 | /// constraints.html#multipart-form-data). 48 | static FormData parse(MimeMultipart multipart, 49 | {Encoding defaultEncoding = utf8}) { 50 | ContentType contentType; 51 | HeaderValue encoding; 52 | HeaderValue disposition; 53 | for (var key in multipart.headers.keys) { 54 | switch (key) { 55 | case 'content-type': 56 | contentType = ContentType.parse(multipart.headers[key]); 57 | break; 58 | 59 | case 'content-transfer-encoding': 60 | encoding = HeaderValue.parse(multipart.headers[key]); 61 | break; 62 | 63 | case 'content-disposition': 64 | disposition = HeaderValue.parse(multipart.headers[key], 65 | preserveBackslash: true); 66 | break; 67 | 68 | default: 69 | break; 70 | } 71 | } 72 | if (disposition == null) { 73 | throw const HttpException( 74 | "Mime Multipart doesn't contain a Content-Disposition header value"); 75 | } 76 | if (encoding != null && 77 | !_transparentEncodings.contains(encoding.value.toLowerCase())) { 78 | // TODO(ajohnsen): Support BASE64, etc. 79 | throw HttpException('Unsupported contentTransferEncoding: ' + encoding.value.toString()); 80 | } 81 | 82 | Stream stream = multipart; 83 | var isText = contentType == null || 84 | contentType.primaryType == 'text' || 85 | contentType.mimeType == 'application/json'; 86 | if (isText) { 87 | Encoding encoding; 88 | if (contentType?.charset != null) { 89 | encoding = Encoding.getByName(contentType.charset); 90 | } 91 | encoding ??= defaultEncoding; 92 | stream = stream.transform(encoding.decoder); 93 | } 94 | return FormData._( 95 | contentType, disposition, encoding, multipart, stream, isText); 96 | } 97 | 98 | final MimeMultipart _mimeMultipart; 99 | 100 | final Stream _stream; 101 | 102 | FormData._( 103 | this.contentType, 104 | this.contentDisposition, 105 | this.contentTransferEncoding, 106 | this._mimeMultipart, 107 | this._stream, 108 | this.isText); 109 | 110 | @override 111 | StreamSubscription listen(void Function(dynamic) onData, 112 | {void Function() onDone, Function onError, bool cancelOnError}) { 113 | return _stream.listen(onData, 114 | onDone: onDone, onError: onError, cancelOnError: cancelOnError); 115 | } 116 | 117 | /// Returns the value for the header named [name]. 118 | /// 119 | /// If there is no header with the provided name, `null` will be returned. 120 | /// 121 | /// Use this method to index other headers available in the original 122 | /// [MimeMultipart]. 123 | String value(String name) { 124 | return _mimeMultipart.headers[name]; 125 | } 126 | } 127 | '''; 128 | } 129 | -------------------------------------------------------------------------------- /lib/template/bootstrap/model/UploadFile.dart: -------------------------------------------------------------------------------- 1 | class UploadFile { 2 | static String content = ''' 3 | import 'dart:io'; 4 | 5 | class UploadFile { 6 | /// The filename of the uploaded file. 7 | final String filename; 8 | 9 | /// The [ContentType] of the uploaded file. 10 | /// 11 | /// For `text/*` and `application/json` the [content] field will a String. 12 | final ContentType contentType; 13 | 14 | /// The content of the file. 15 | /// 16 | /// Either a [String] or a [List]. 17 | final dynamic content; 18 | 19 | UploadFile(this.contentType, this.filename, this.content); 20 | 21 | Map toJson() { 22 | return { 23 | 'filename': filename, 24 | 'contentType': contentType.toString(), 25 | 'content': 'UploadFile Content' 26 | }; 27 | } 28 | } 29 | '''; 30 | } 31 | -------------------------------------------------------------------------------- /lib/template/bootstrap/redis/Redis.dart: -------------------------------------------------------------------------------- 1 | class Redis { 2 | static String content = ''' 3 | import 'package:redis/redis.dart'; 4 | 5 | class Redis { 6 | RedisConnection _conn; 7 | 8 | Command _command; 9 | 10 | String ok = 'OK'; 11 | 12 | Redis() { 13 | _conn = RedisConnection(); 14 | } 15 | 16 | Future connect(String host, int port) async { 17 | _command = await _conn.connect(host, port); 18 | } 19 | 20 | Future connectSecure(String host, int port) async { 21 | _command = await _conn.connectSecure(host, port); 22 | } 23 | 24 | Future close() async => await _conn.close(); 25 | 26 | Future sendObject(List params) async => 27 | await _command.send_object(params); 28 | 29 | /// return count by del; 30 | Future del(List keys) async { 31 | dynamic count = await _getRes('DEL', keys, []); 32 | return count as int; 33 | } 34 | 35 | Future dump(String key) async => await sendObject(['DUMP', key]); 36 | 37 | /// return count of keys which exists 38 | Future exists(List keys) async { 39 | dynamic count = await _getRes('EXISTS', keys, []); 40 | return count as int; 41 | } 42 | 43 | Future expire(String key, int seconds) async => 44 | await sendObject(['EXPIRE', key, seconds]); 45 | 46 | Future expireat(String key, int unixTime) async => 47 | await sendObject(['EXPIREAT', key, unixTime]); 48 | 49 | Future keys(String pattern) async => 50 | await sendObject(['KEYS', pattern]); 51 | 52 | Future migrate(String host, int port, String key, int destinationDB, 53 | int timeout) async => 54 | _command 55 | .send_object(['MIGRATE', host, port, key, destinationDB, timeout]); 56 | 57 | Future move(String key, int dbIndex) async => 58 | await sendObject(['MOVE', key, dbIndex]); 59 | 60 | Future persist(String key) async => 61 | await sendObject(['PERSIST', key]); 62 | 63 | Future pexpire(String key, int seconds) async => 64 | await sendObject(['PEXPIRE', key, seconds]); 65 | 66 | Future pexpireat(String key, int unixTime) async => 67 | await sendObject(['PEXPIREAT', key, unixTime]); 68 | 69 | Future pttl(String key) async => await sendObject(['PTTL', key]); 70 | 71 | Future randomkey() async => await sendObject(['RANDOMKEY']); 72 | 73 | Future rename(String oldkey, String newkey) async => 74 | await sendObject(['RENAME', oldkey, newkey]); 75 | 76 | Future renamenx(String oldkey, String newkey) async => 77 | await sendObject(['RENAMENX', oldkey, newkey]); 78 | 79 | Future sort(String key) async => await sendObject(['SORT', key]); 80 | 81 | Future ttl(String key) async => await sendObject(['TTL', key]); 82 | 83 | Future type(String key) async => await sendObject(['TYPE', key]); 84 | 85 | Future append(String key, String value) async => 86 | await sendObject(['APPEND', key, value]); 87 | 88 | Future bitcount(String key) async => 89 | await sendObject(['BITCOUNT', key]); 90 | 91 | Future decr(String key) async => await sendObject(['DECR', key]); 92 | 93 | Future decrby(String key, int decrement) async => 94 | await sendObject(['DECRBY', key, decrement]); 95 | 96 | Future get(String key) async => await sendObject(['GET', key]); 97 | 98 | Future getbit(String key, int offset) async => 99 | await sendObject(['GETBIT', key, offset]); 100 | 101 | Future getrange(String key, int startOffset, int endOffset) async => 102 | await sendObject(['GETRANGE', key, startOffset, endOffset]); 103 | 104 | Future getset(String key, String value) async => 105 | await sendObject(['GETSET', key, value]); 106 | 107 | Future incr(String key) async => await sendObject(['INCR', key]); 108 | 109 | Future incrby(String key, int increment) async => 110 | await sendObject(['INCRBY', key, increment]); 111 | 112 | Future incrbyfloat(String key, double increment) async => 113 | await sendObject(['INCRBYFLOAT', key, increment]); 114 | 115 | Future mget(List keys) async => 116 | await _getRes('MGET', keys, []); 117 | 118 | Future mset(List keys) async => 119 | await _getRes('MSET', keys, []); 120 | 121 | Future msetnx(List keys) async => 122 | await _getRes('MSETNX', keys, []); 123 | 124 | Future psetex(String key, int seconds, String value) async => 125 | await sendObject(['PSETEX', key, seconds, value]); 126 | 127 | Future set(String key, String value) async => 128 | await sendObject(['SET', key, value]); 129 | 130 | Future setbit(String key, int offset, List value) async => 131 | await sendObject(['SETBIT', key, offset, value]); 132 | 133 | Future setex(String key, int seconds, String value) async => 134 | await sendObject(['SETEX', key, seconds, value]); 135 | 136 | Future setnx(String key, String value) async => 137 | await sendObject(['SETNX', key, value]); 138 | 139 | Future setrange(String key, int offset, String value) async => 140 | await sendObject(['SETRANGE', key, offset, value]); 141 | 142 | Future strlen(String key) async => await sendObject(['STRLEN', key]); 143 | 144 | Future hdel(String key, List fields) async => 145 | await _getRes('HDEL', [key], fields); 146 | 147 | Future hexists(String key, String field) async => 148 | await sendObject(['HEXISTS', key, field]); 149 | 150 | Future hget(String key, String field) async => 151 | await sendObject(['HGET', key, field]); 152 | 153 | Future hgetall(String key) async => 154 | await sendObject(['HGETALL', key]); 155 | 156 | Future hincrby(String key, String field, int value) async => 157 | await sendObject(['HINCRBY', key, field, value]); 158 | 159 | Future hincrbyfloat(String key, String field, double value) async => 160 | await sendObject(['HINCRBYFLOAT', key, field, value]); 161 | 162 | Future hkeys(String key) async => await sendObject(['HKEYS', key]); 163 | 164 | Future hlen(String key) async => await sendObject(['HLEN', key]); 165 | 166 | Future hmget(String key, List fields) async => 167 | await _getRes('HMGET', [key], fields); 168 | 169 | Future hmset(String key, Map hash) async { 170 | List l = []; 171 | l.add('HMSET'); 172 | l.add(key); 173 | hash.forEach((key1, value1) { 174 | l.add(key1); 175 | l.add(value1); 176 | }); 177 | 178 | await sendObject(l); 179 | } 180 | 181 | Future hset(String key, String field, String value) async => 182 | await sendObject(['HSET', key, field, value]); 183 | 184 | Future hsetnx(String key, String field, String value) async => 185 | await sendObject(['HSETNX', key, field, value]); 186 | 187 | Future hvals(String key) async => await sendObject(['HVALS', key]); 188 | 189 | Future blpop(List args) async => 190 | await sendObject(['BLPOP', args]); 191 | 192 | Future brpop(List args) async => 193 | await sendObject(['BRPOP', args]); 194 | 195 | Future brpoplpush( 196 | String source, String destination, int timeout) async => 197 | await sendObject(['BRPOPLPUSH', source, destination, timeout]); 198 | 199 | Future lindex(String key, int index) async => 200 | await sendObject(['LINDEX', key, index]); 201 | 202 | Future llen(String key) async => await sendObject(['LLEN', key]); 203 | 204 | Future lpop(String key) async => await sendObject(['LPOP', key]); 205 | 206 | Future lpush(String key, List strings) async => 207 | await _getRes('LPUSH', [key], strings); 208 | 209 | Future lpushx(String key, List strings) async => 210 | await _getRes('LPUSHX', [key], strings); 211 | 212 | Future lrange(String key, int start, int stop) async => 213 | await sendObject(['LRANGE', key, start, stop]); 214 | 215 | Future lrem(String key, int count, String value) async => 216 | await sendObject(['LREM', key, count, value]); 217 | 218 | Future lset(String key, int index, String value) async => 219 | await sendObject(['LSET', key, index, value]); 220 | 221 | Future ltrim(String key, int start, int stop) async => 222 | await sendObject(['LTRIM', key, start, stop]); 223 | 224 | Future rpop(String key) async => await sendObject(['RPOP', key]); 225 | 226 | Future rpoplpush(String srckey, String dstkey) async => 227 | await sendObject(['RPOPLPUSH', srckey, dstkey]); 228 | 229 | Future rpush(String key, List strings) async => 230 | await _getRes('RPUSH', [key], strings); 231 | 232 | Future rpushx(String key, List strings) async => 233 | await _getRes('RPUSHX', [key], strings); 234 | 235 | Future sadd(String key, List members) async => 236 | await _getRes('SADD', [key], members); 237 | 238 | Future scard(String key) async => await sendObject(['SCARD', key]); 239 | 240 | Future sdiff(List keys) async => 241 | await _getRes('SDIFF', keys, []); 242 | 243 | Future sdiffstore(String dstkey, List keys) async => 244 | await _getRes('SDIFFSTORE', [dstkey], keys); 245 | 246 | Future sinter(List keys) async => 247 | await _getRes('SINTER', keys, []); 248 | 249 | Future sinterstore(String dstkey, List keys) async => 250 | await _getRes('SINTERSTORE', [dstkey], keys); 251 | 252 | Future sismember(String key, String member) async => 253 | await sendObject(['SISMEMBER', key, member]); 254 | 255 | Future smembers(String key) async => 256 | await sendObject(['SMEMBERS', key]); 257 | 258 | Future smove(String srckey, String dstkey, String member) async => 259 | await sendObject(['SMOVE', srckey, dstkey, member]); 260 | 261 | Future spop(String key) async => await sendObject(['SPOP', key]); 262 | 263 | Future srandmember(String key) async => 264 | await sendObject(['SRANDMEMBER', key]); 265 | 266 | Future srem(String key, List member) async => 267 | await _getRes('SREM', [key], member); 268 | 269 | Future sunion(List keys) async => 270 | await _getRes('SUNION', keys, []); 271 | 272 | Future sunionstore(String dstkey, List keys) async => 273 | await _getRes('SUNIONSTORE', [dstkey], keys); 274 | 275 | Future zadd(String key, double score, String member) async => 276 | await sendObject(['ZADD', key, score, member]); 277 | 278 | Future zcard(String key) async => await sendObject(['ZCARD', key]); 279 | 280 | Future zcount(String key, double min, double max) async => 281 | await sendObject(['ZCOUNT', key, min, max]); 282 | 283 | Future zincrby(String key, double increment, String member) async => 284 | await sendObject(['ZINCRBY', key, increment, member]); 285 | 286 | Future zrange(String key, int start, int stop) async => 287 | await sendObject(['ZRANGE', key, start, stop]); 288 | 289 | Future zrangebyscore(String key, double min, double max) async => 290 | await sendObject(['ZRANGEBYSCORE', key, min, max]); 291 | 292 | Future zrank(String key, String member) async => 293 | await sendObject(['ZRANK', key, member]); 294 | 295 | Future zrem(String key, List members) async => 296 | await _getRes('ZREM', [key], members); 297 | 298 | Future zremrangebyrank(String key, int start, int stop) async => 299 | await sendObject(['ZREMRANGEBYRANK', key, start, stop]); 300 | 301 | Future zremrangebyscore(String key, double min, double max) async => 302 | await sendObject(['ZREMRANGEBYSCORE', key, min, max]); 303 | 304 | Future zrevrange(String key, int start, int stop) async => 305 | await sendObject(['ZREVRANGE', key, start, stop]); 306 | 307 | Future zrevrangebyscore(String key, double max, double min) async => 308 | await sendObject(['ZREVRANGEBYSCORE', key, max, min]); 309 | 310 | Future zrevrank(String key, String member) async => 311 | await sendObject(['ZREVRANK', key, member]); 312 | 313 | Future zscore(String key, String member) async => 314 | await sendObject(['ZSCORE', key, member]); 315 | 316 | Future zunionstore(String dstkey, List sets) async => 317 | await _getRes('ZUNIONSTORE', [dstkey], sets); 318 | 319 | Future zinterstore(String dstkey, List sets) async => 320 | await _getRes('ZINTERSTORE', [dstkey], sets); 321 | 322 | Future psubscribe(List patterns) async => 323 | await _getRes('PSUBSCRIBE', patterns, []); 324 | 325 | Future punsubscribe() async => await sendObject(['PUNSUBSCRIBE']); 326 | 327 | Future subscribe() async => await sendObject(['SUBSCRIBE']); 328 | 329 | Future unsubscribe() async => await sendObject(['UNSUBSCRIBE']); 330 | 331 | Future discard() async => await sendObject(['DISCARD']); 332 | 333 | Future exec() async => await sendObject(['EXEC']); 334 | 335 | Future multi() async => await sendObject(['MULTI']); 336 | 337 | Future unwatch() async => await sendObject(['UNWATCH']); 338 | 339 | Future watch(List keys) async => 340 | await _getRes('WATCH', keys, []); 341 | 342 | Future scriptFlush() async => await sendObject(['SCRIPT FLUSH']); 343 | 344 | Future scriptKill() async => await sendObject(['SCRIPT KILL']); 345 | 346 | /// return OK if verify auth success, otherwise err; 347 | Future auth(String password) async => 348 | await sendObject(['AUTH', password]); 349 | 350 | Future echo(String string) async => 351 | await sendObject(['ECHO', string]); 352 | 353 | Future ping(String message) async => 354 | await sendObject(['PING', message]); 355 | 356 | Future quit() async => await sendObject(['QUIT']); 357 | 358 | Future select(int index) async => 359 | await sendObject(['SELECT', index]); 360 | 361 | Future bgrewriteaof() async => await sendObject(['BGREWRITEAOF']); 362 | 363 | Future bgsave() async => await sendObject(['BGSAVE']); 364 | 365 | Future clientGetname() async => await sendObject(['CLIENT GETNAME']); 366 | 367 | Future clientKill(String ipPort) async => 368 | await sendObject(['CLIENT KILL', ipPort]); 369 | 370 | Future clientList() async => await sendObject(['CLIENT LIST']); 371 | 372 | Future clientSetname(String name) async => 373 | await sendObject(['CLIENT SETNAME', name]); 374 | 375 | Future configGet(String pattern) async => 376 | await sendObject(['CONFIG GET', pattern]); 377 | 378 | Future configResetstat() async => 379 | await sendObject(['CONFIG RESETSTAT']); 380 | 381 | Future configRewrite() async => await sendObject(['CONFIG REWRITE']); 382 | 383 | Future configSet(String parameter, String value) async => 384 | await sendObject(['CONFIG SET', parameter, value]); 385 | 386 | Future dbsize() async => await sendObject(['DBSIZE']); 387 | 388 | Future flushall() async => await sendObject(['FLUSHALL']); 389 | 390 | Future flushdb() async => await sendObject(['FLUSHDB']); 391 | 392 | Future info() async => await sendObject(['INFO']); 393 | 394 | Future lastsave() async => await sendObject(['LASTSAVE']); 395 | 396 | Future save() async => await sendObject(['SAVE']); 397 | 398 | Future shutdown() async => await sendObject(['SHUTDOWN']); 399 | 400 | Future slaveof(String host, int port) async => 401 | await sendObject(['SLAVEOF', host, port]); 402 | 403 | Future sync() async => await sendObject(['SYNC']); 404 | 405 | Future time(String key) async => await sendObject(['TIME', key]); 406 | 407 | Future _getRes( 408 | String commandName, List param1, List param2) async { 409 | List param = []; 410 | param.add(commandName); 411 | if (param1.isNotEmpty) param.addAll(param1); 412 | if (param2.isNotEmpty) param.addAll(param2); 413 | 414 | return await sendObject(param); 415 | } 416 | 417 | /// operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种: 418 | Future bitop( 419 | String operation, String destkey, List keys) async => 420 | await _getRes('BITOP', [operation, destkey], keys); 421 | 422 | /// postion 可以是 BEFORE, AFTER 这2种操作中的任意一种 423 | Future linsert( 424 | String key, String postion, String pivot, String value) async => 425 | await _getRes('LINSERT', [key, postion, pivot, value], []); 426 | 427 | Future object(String subcommand, List args) async => 428 | await _getRes('OBJECT', [subcommand], args); 429 | 430 | Future hscan(String key, String cursor, List pattern, 431 | List count) async => 432 | await _getRes('HSCAN', []..addAll([key, cursor])..addAll(pattern), count); 433 | 434 | Future sscan(String key, String cursor, List pattern, 435 | List count) async => 436 | await _getRes('SSCAN', []..addAll([key, cursor])..addAll(pattern), count); 437 | 438 | Future zscan(String key, String cursor, List pattern, 439 | List count) async => 440 | await _getRes('ZSCAN', []..addAll([key, cursor])..addAll(pattern), count); 441 | 442 | Future scan( 443 | String cursor, List pattern, List count) async => 444 | await _getRes('SCAN', []..addAll([cursor])..addAll(pattern), count); 445 | 446 | Future restore(String key, int ttl, String serializedValue) async => 447 | await _getRes('RESTORE', [key, ttl, serializedValue], []); 448 | 449 | Future eval(String script, int numkeys, List keys, 450 | List args) async => 451 | await _getRes('EVAL', [script, numkeys], []..addAll(keys)..addAll(args)); 452 | 453 | Future publish(String channel, String message) async => 454 | await _getRes('PUBLISH', [channel, message], []); 455 | 456 | Future evalsha(String sha1, int numkeys, List keys, 457 | List args) async => 458 | await _getRes('EVALSHA', [sha1, numkeys], []..addAll(keys)..addAll(args)); 459 | 460 | Future pubsub(String subcommand, List args) async => 461 | await _getRes('PUBSUB', [subcommand], args); 462 | 463 | Future scriptExists(List args) async => 464 | await _getRes('SCRIPT', ['EXISTS'], args); 465 | 466 | Future scriptLoad(String script) async => 467 | await _getRes('SCRIPT', ['LOAD'], [script]); 468 | 469 | Future debugObject(String key) async => 470 | await _getRes('DEBUG', ['OBJECT'], [key]); 471 | 472 | Future debugSegfault() async => 473 | await _getRes('DEBUG', ['SEGFAULT'], []); 474 | 475 | Future monitor() async => await _getRes('MONITOR', [], []); 476 | 477 | Future psync(String masterRunId, int offset) async => 478 | await _getRes('PSYNC', [masterRunId], [offset]); 479 | 480 | Future slowlog(String subcommand, List args) async => 481 | await _getRes('SLOWLOG', [subcommand], args); 482 | } 483 | '''; 484 | } 485 | -------------------------------------------------------------------------------- /lib/template/env/Env.dart: -------------------------------------------------------------------------------- 1 | class Env { 2 | static String content = ''' 3 | # db config 4 | dbHost: localhost 5 | dbPort: 3306 6 | dbUser: root 7 | dbPassword: root 8 | dbName: example 9 | 10 | # ssl config 11 | ssl: off 12 | sslCertificate: cert/cert.pem 13 | sslCertificateKey: cert/key.pem 14 | '''; 15 | } 16 | -------------------------------------------------------------------------------- /lib/template/extend/model/Agent.dart: -------------------------------------------------------------------------------- 1 | class Agent { 2 | static String content = ''' 3 | import '../../bootstrap/meta/FieldMeta.dart'; 4 | import '../../bootstrap/meta/TableMeta.dart'; 5 | 6 | @TableMeta(comment: '合伙人表', engine: 'InnoDB') 7 | class Agent { 8 | @FieldMeta(autoIncrease: 'true', key: 'primary key') 9 | int id; 10 | 11 | @FieldMeta(comment: '合伙人id', length: '40', def: '', key: 'unique key') 12 | String agentNo; 13 | 14 | @FieldMeta(comment: '手机号', length: '11', def: '', key: 'key') 15 | String agentMobile; 16 | 17 | @FieldMeta(comment: '姓名', length: '80', def: '') 18 | String agentName; 19 | 20 | @FieldMeta(comment: '密码', length: '40', def: '') 21 | String password; 22 | 23 | @FieldMeta(comment: '创建时间', type: 'bigint', def: '0') 24 | int createTime; 25 | 26 | @FieldMeta(comment: '删除时间', type: 'bigint', def: '0') 27 | int deleteTime; 28 | } 29 | '''; 30 | } 31 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | _fe_analyzer_shared: 5 | dependency: transitive 6 | description: 7 | name: _fe_analyzer_shared 8 | url: "https://pub.flutter-io.cn" 9 | source: hosted 10 | version: "22.0.0" 11 | analyzer: 12 | dependency: transitive 13 | description: 14 | name: analyzer 15 | url: "https://pub.flutter-io.cn" 16 | source: hosted 17 | version: "1.7.0" 18 | args: 19 | dependency: transitive 20 | description: 21 | name: args 22 | url: "https://pub.flutter-io.cn" 23 | source: hosted 24 | version: "2.1.1" 25 | async: 26 | dependency: transitive 27 | description: 28 | name: async 29 | url: "https://pub.flutter-io.cn" 30 | source: hosted 31 | version: "2.7.0" 32 | boolean_selector: 33 | dependency: transitive 34 | description: 35 | name: boolean_selector 36 | url: "https://pub.flutter-io.cn" 37 | source: hosted 38 | version: "2.1.0" 39 | charcode: 40 | dependency: transitive 41 | description: 42 | name: charcode 43 | url: "https://pub.flutter-io.cn" 44 | source: hosted 45 | version: "1.3.1" 46 | cli_util: 47 | dependency: transitive 48 | description: 49 | name: cli_util 50 | url: "https://pub.flutter-io.cn" 51 | source: hosted 52 | version: "0.3.1" 53 | collection: 54 | dependency: transitive 55 | description: 56 | name: collection 57 | url: "https://pub.flutter-io.cn" 58 | source: hosted 59 | version: "1.15.0" 60 | convert: 61 | dependency: transitive 62 | description: 63 | name: convert 64 | url: "https://pub.flutter-io.cn" 65 | source: hosted 66 | version: "3.0.1" 67 | coverage: 68 | dependency: transitive 69 | description: 70 | name: coverage 71 | url: "https://pub.flutter-io.cn" 72 | source: hosted 73 | version: "1.0.3" 74 | crypto: 75 | dependency: transitive 76 | description: 77 | name: crypto 78 | url: "https://pub.flutter-io.cn" 79 | source: hosted 80 | version: "3.0.1" 81 | file: 82 | dependency: transitive 83 | description: 84 | name: file 85 | url: "https://pub.flutter-io.cn" 86 | source: hosted 87 | version: "6.1.2" 88 | frontend_server_client: 89 | dependency: transitive 90 | description: 91 | name: frontend_server_client 92 | url: "https://pub.flutter-io.cn" 93 | source: hosted 94 | version: "2.1.0" 95 | glob: 96 | dependency: transitive 97 | description: 98 | name: glob 99 | url: "https://pub.flutter-io.cn" 100 | source: hosted 101 | version: "2.0.1" 102 | http_multi_server: 103 | dependency: transitive 104 | description: 105 | name: http_multi_server 106 | url: "https://pub.flutter-io.cn" 107 | source: hosted 108 | version: "3.0.1" 109 | http_parser: 110 | dependency: transitive 111 | description: 112 | name: http_parser 113 | url: "https://pub.flutter-io.cn" 114 | source: hosted 115 | version: "4.0.0" 116 | io: 117 | dependency: transitive 118 | description: 119 | name: io 120 | url: "https://pub.flutter-io.cn" 121 | source: hosted 122 | version: "1.0.0" 123 | js: 124 | dependency: transitive 125 | description: 126 | name: js 127 | url: "https://pub.flutter-io.cn" 128 | source: hosted 129 | version: "0.6.3" 130 | logging: 131 | dependency: transitive 132 | description: 133 | name: logging 134 | url: "https://pub.flutter-io.cn" 135 | source: hosted 136 | version: "1.0.1" 137 | matcher: 138 | dependency: transitive 139 | description: 140 | name: matcher 141 | url: "https://pub.flutter-io.cn" 142 | source: hosted 143 | version: "0.12.10" 144 | meta: 145 | dependency: transitive 146 | description: 147 | name: meta 148 | url: "https://pub.flutter-io.cn" 149 | source: hosted 150 | version: "1.4.0" 151 | mime: 152 | dependency: transitive 153 | description: 154 | name: mime 155 | url: "https://pub.flutter-io.cn" 156 | source: hosted 157 | version: "1.0.0" 158 | mysql1: 159 | dependency: "direct main" 160 | description: 161 | name: mysql1 162 | url: "https://pub.flutter-io.cn" 163 | source: hosted 164 | version: "0.19.2" 165 | node_preamble: 166 | dependency: transitive 167 | description: 168 | name: node_preamble 169 | url: "https://pub.flutter-io.cn" 170 | source: hosted 171 | version: "2.0.1" 172 | package_config: 173 | dependency: transitive 174 | description: 175 | name: package_config 176 | url: "https://pub.flutter-io.cn" 177 | source: hosted 178 | version: "2.0.0" 179 | path: 180 | dependency: transitive 181 | description: 182 | name: path 183 | url: "https://pub.flutter-io.cn" 184 | source: hosted 185 | version: "1.8.0" 186 | pedantic: 187 | dependency: "direct dev" 188 | description: 189 | name: pedantic 190 | url: "https://pub.flutter-io.cn" 191 | source: hosted 192 | version: "1.11.1" 193 | pool: 194 | dependency: transitive 195 | description: 196 | name: pool 197 | url: "https://pub.flutter-io.cn" 198 | source: hosted 199 | version: "1.5.0" 200 | process_run: 201 | dependency: "direct main" 202 | description: 203 | name: process_run 204 | url: "https://pub.flutter-io.cn" 205 | source: hosted 206 | version: "0.12.1+1" 207 | pub_semver: 208 | dependency: transitive 209 | description: 210 | name: pub_semver 211 | url: "https://pub.flutter-io.cn" 212 | source: hosted 213 | version: "2.0.0" 214 | shelf: 215 | dependency: transitive 216 | description: 217 | name: shelf 218 | url: "https://pub.flutter-io.cn" 219 | source: hosted 220 | version: "1.1.4" 221 | shelf_packages_handler: 222 | dependency: transitive 223 | description: 224 | name: shelf_packages_handler 225 | url: "https://pub.flutter-io.cn" 226 | source: hosted 227 | version: "3.0.0" 228 | shelf_static: 229 | dependency: transitive 230 | description: 231 | name: shelf_static 232 | url: "https://pub.flutter-io.cn" 233 | source: hosted 234 | version: "1.0.0" 235 | shelf_web_socket: 236 | dependency: transitive 237 | description: 238 | name: shelf_web_socket 239 | url: "https://pub.flutter-io.cn" 240 | source: hosted 241 | version: "1.0.1" 242 | source_map_stack_trace: 243 | dependency: transitive 244 | description: 245 | name: source_map_stack_trace 246 | url: "https://pub.flutter-io.cn" 247 | source: hosted 248 | version: "2.1.0" 249 | source_maps: 250 | dependency: transitive 251 | description: 252 | name: source_maps 253 | url: "https://pub.flutter-io.cn" 254 | source: hosted 255 | version: "0.10.10" 256 | source_span: 257 | dependency: transitive 258 | description: 259 | name: source_span 260 | url: "https://pub.flutter-io.cn" 261 | source: hosted 262 | version: "1.8.1" 263 | stack_trace: 264 | dependency: transitive 265 | description: 266 | name: stack_trace 267 | url: "https://pub.flutter-io.cn" 268 | source: hosted 269 | version: "1.10.0" 270 | stream_channel: 271 | dependency: transitive 272 | description: 273 | name: stream_channel 274 | url: "https://pub.flutter-io.cn" 275 | source: hosted 276 | version: "2.1.0" 277 | string_scanner: 278 | dependency: transitive 279 | description: 280 | name: string_scanner 281 | url: "https://pub.flutter-io.cn" 282 | source: hosted 283 | version: "1.1.0" 284 | synchronized: 285 | dependency: transitive 286 | description: 287 | name: synchronized 288 | url: "https://pub.flutter-io.cn" 289 | source: hosted 290 | version: "3.0.0" 291 | term_glyph: 292 | dependency: transitive 293 | description: 294 | name: term_glyph 295 | url: "https://pub.flutter-io.cn" 296 | source: hosted 297 | version: "1.2.0" 298 | test: 299 | dependency: "direct dev" 300 | description: 301 | name: test 302 | url: "https://pub.flutter-io.cn" 303 | source: hosted 304 | version: "1.17.9" 305 | test_api: 306 | dependency: transitive 307 | description: 308 | name: test_api 309 | url: "https://pub.flutter-io.cn" 310 | source: hosted 311 | version: "0.4.1" 312 | test_core: 313 | dependency: transitive 314 | description: 315 | name: test_core 316 | url: "https://pub.flutter-io.cn" 317 | source: hosted 318 | version: "0.3.29" 319 | typed_data: 320 | dependency: transitive 321 | description: 322 | name: typed_data 323 | url: "https://pub.flutter-io.cn" 324 | source: hosted 325 | version: "1.3.0" 326 | vm_service: 327 | dependency: transitive 328 | description: 329 | name: vm_service 330 | url: "https://pub.flutter-io.cn" 331 | source: hosted 332 | version: "7.1.0" 333 | watcher: 334 | dependency: transitive 335 | description: 336 | name: watcher 337 | url: "https://pub.flutter-io.cn" 338 | source: hosted 339 | version: "1.0.0" 340 | web_socket_channel: 341 | dependency: transitive 342 | description: 343 | name: web_socket_channel 344 | url: "https://pub.flutter-io.cn" 345 | source: hosted 346 | version: "2.1.0" 347 | webkit_inspection_protocol: 348 | dependency: transitive 349 | description: 350 | name: webkit_inspection_protocol 351 | url: "https://pub.flutter-io.cn" 352 | source: hosted 353 | version: "1.0.0" 354 | yaml: 355 | dependency: "direct main" 356 | description: 357 | name: yaml 358 | url: "https://pub.flutter-io.cn" 359 | source: hosted 360 | version: "3.1.0" 361 | sdks: 362 | dart: ">=2.12.0 <3.0.0" 363 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart_mars 2 | description: A sample command-line application. 3 | version: 1.0.5 4 | homepage: https://github.com/tangpanqing/dart_mars 5 | 6 | environment: 7 | sdk: '>=2.10.0 <3.0.0' 8 | 9 | dependencies: 10 | process_run: ^0.12.1 11 | yaml: ^3.1.0 12 | mysql1: ^0.19.2 13 | 14 | dev_dependencies: 15 | pedantic: ^1.9.0 16 | test: ^1.14.4 17 | -------------------------------------------------------------------------------- /test/check.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | // ignore: always_declare_return_types 4 | main() { 5 | File file1 = File( 6 | 'D:\\vs_project\\dart_mars\\lib\\template\\bootstrap\\redis\\Redis.dart'); 7 | File file2 = File('D:\\vs_project\\dart_mars_doc\\src\\zh\\use\\cache.md'); 8 | 9 | //print(file1.readAsStringSync()); 10 | //print(file2.readAsStringSync()); 11 | 12 | var matchs1 = RegExp(r'Future.*?\(', dotAll: true, multiLine: true) 13 | .allMatches(file1.readAsStringSync()); 14 | 15 | List list1 = []; 16 | matchs1.forEach((element) { 17 | String s = element.group(0).toString().split(' ').last.replaceAll('(', ''); 18 | list1.add(s.trim()); 19 | }); 20 | list1.remove('connect'); 21 | list1.remove('connectSecure'); 22 | list1.remove('close'); 23 | list1.remove('sendObject'); 24 | list1.remove('_getRes'); 25 | 26 | List list22 = file2.readAsStringSync().split('|'); 27 | list22.removeAt(0); 28 | 29 | List list2 = []; 30 | list22.forEach((element) { 31 | String s = element 32 | .replaceAll(RegExp('[键字符串散列表列表集合有序集合脚本服务器发布订阅事务脚本连接-]'), '') 33 | .trim(); 34 | if (s.isNotEmpty) { 35 | if (!s.contains(' ')) { 36 | list2.add(s.trim()); 37 | } else { 38 | List ss = s.split(' '); 39 | 40 | String t = 41 | ss[0] + ss[1].substring(0, 1).toUpperCase() + ss[1].substring(1); 42 | list2.add(t); 43 | } 44 | } 45 | }); 46 | 47 | List all = ListHelper.merge(list1, list2); 48 | all = ListHelper.unique(all); 49 | 50 | List list1_meiyou = ListHelper.diff(all, list1); 51 | print(list1_meiyou); 52 | 53 | List list2_meiyou = ListHelper.diff(all, list2); 54 | print(list2_meiyou); 55 | } 56 | 57 | class ListHelper { 58 | static List merge(List a, List b) { 59 | List c = []; 60 | c.addAll(a); 61 | c.addAll(b); 62 | return c; 63 | } 64 | 65 | static List unique(List c) { 66 | Set temp = {}; 67 | temp.addAll(c); 68 | return temp.map((e) => e.toString()).toList(); 69 | } 70 | 71 | // a有, b没有 72 | static List diff(List a, List b) { 73 | List c = []; 74 | 75 | a.forEach((element) { 76 | if (!b.contains(element)) { 77 | c.add(element); 78 | } 79 | }); 80 | 81 | return c; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /test/test.dart: -------------------------------------------------------------------------------- 1 | main() async {} 2 | -------------------------------------------------------------------------------- /test/test_async.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:isolate'; 3 | 4 | main() async { 5 | List taskList = [ 6 | TaskItem('1', 'param1'), 7 | TaskItem('2', 'param2'), 8 | TaskItem('3', 'param1'), 9 | TaskItem('4', 'param2'), 10 | TaskItem('5', 'param1'), 11 | TaskItem('6', 'param2'), 12 | TaskItem('7', 'param1'), 13 | TaskItem('8', 'param2'), 14 | TaskItem('9', 'param1'), 15 | TaskItem('0', 'param2'), 16 | ]; 17 | 18 | print(DateTime.now()); 19 | 20 | MultiTask.run( 21 | taskList: taskList, 22 | taskFunc: taskFunc, 23 | onCompletedItem: (TaskRes taskRes) => print(taskRes.res), 24 | onCompletedAll: (List taskResList) => print(DateTime.now()), 25 | ); 26 | } 27 | 28 | void taskFunc(TaskMessage taskMessage) async { 29 | sleep(Duration(seconds: 3)); 30 | 31 | String res = 'res'; 32 | 33 | taskMessage.sendPort.send(TaskRes(taskMessage.taskItem.key, res)); 34 | } 35 | 36 | class MultiTask { 37 | static void run( 38 | {List taskList, 39 | Function taskFunc, 40 | Function onCompletedItem, 41 | Function onCompletedAll}) async { 42 | ReceivePort receivePort = new ReceivePort(); 43 | 44 | Map mapParam = {}; 45 | for (int i = 0; i < taskList.length; i++) { 46 | TaskItem taskItem = taskList[i]; 47 | mapParam[taskItem.key] = await Isolate.spawn( 48 | taskFunc, TaskMessage(receivePort.sendPort, taskItem)); 49 | } 50 | 51 | List taskResList = []; 52 | receivePort.listen((message) async { 53 | TaskRes taskRes = message as TaskRes; 54 | if (null != onCompletedItem) await onCompletedItem(taskRes); 55 | taskResList.add(taskRes); 56 | mapParam[taskRes.key].kill(); 57 | if (taskResList.length == taskList.length) { 58 | receivePort.close(); 59 | if (null != onCompletedAll) await onCompletedAll(taskResList); 60 | } 61 | }); 62 | } 63 | } 64 | 65 | class TaskMessage { 66 | SendPort sendPort; 67 | TaskItem taskItem; 68 | TaskMessage(this.sendPort, this.taskItem); 69 | } 70 | 71 | class TaskItem { 72 | String key; 73 | String param; 74 | 75 | TaskItem(this.key, this.param); 76 | } 77 | 78 | class TaskRes { 79 | String key; 80 | String res; 81 | 82 | TaskRes(this.key, this.res); 83 | } 84 | --------------------------------------------------------------------------------