{"id":16479147,"url":"https://github.com/gudaoxuri/dew-common","last_synced_at":"2025-03-16T18:31:36.132Z","repository":{"id":45452077,"uuid":"79693438","full_name":"gudaoxuri/dew-common","owner":"gudaoxuri","description":"Java common tools collection, support for GraalVM","archived":false,"fork":false,"pushed_at":"2024-04-12T13:45:49.000Z","size":845,"stargazers_count":59,"open_issues_count":0,"forks_count":29,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-02-27T12:08:44.153Z","etag":null,"topics":["bean","dew","encryption","interpreter","json","shell"],"latest_commit_sha":null,"homepage":"https://gudaoxuri.github.io/dew-common/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gudaoxuri.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2017-01-22T04:23:56.000Z","updated_at":"2024-11-28T02:11:38.000Z","dependencies_parsed_at":"2024-01-14T16:31:34.115Z","dependency_job_id":"dad1d8cc-1ebd-494b-97b7-4356486b1ae0","html_url":"https://github.com/gudaoxuri/dew-common","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gudaoxuri%2Fdew-common","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gudaoxuri%2Fdew-common/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gudaoxuri%2Fdew-common/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gudaoxuri%2Fdew-common/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gudaoxuri","download_url":"https://codeload.github.com/gudaoxuri/dew-common/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243826788,"owners_count":20354220,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bean","dew","encryption","interpreter","json","shell"],"created_at":"2024-10-11T12:51:12.285Z","updated_at":"2025-03-16T18:31:35.292Z","avatar_url":"https://github.com/gudaoxuri.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"image::https://img.shields.io/travis/gudaoxuri/dew-common.svg[link=\"https://travis-ci.org/gudaoxuri/dew-common\"]\nimage:https://api.codacy.com/project/badge/Grade/3d8cdfe8b94a4ca29666398b19a84dd2[\"Codacy code quality\", link=\"https://www.codacy.com/app/gudaoxuri/dew-common?utm_source=github.com\u0026utm_medium=referral\u0026utm_content=gudaoxuri/dew-common\u0026utm_campaign=Badge_Grade\"]\nimage:https://img.shields.io/badge/license-ASF2-blue.svg[\"Apache License 2\",link=\"https://www.apache.org/licenses/LICENSE-2.0.txt\"]\nimage:https://maven-badges.herokuapp.com/maven-central/com.ecfront.dew/common/badge.svg[\"Maven Central\",link=\"https://maven-badges.herokuapp.com/maven-central/com.ecfront.dew/common/\"]\n\nDew Common的理念是简化Java开发中最常用的操作，同时尽可能少地引入第三方包，做到通用、易用、精简。\n\n== 功能\n\n. Json与Java对象互转，支持泛型\n. Java Bean操作，Bean复制、反射获取/设置注解、字段、方法等\n. Java Class扫描操作，根据注解或名称过滤\n. Shell脚本操作，Shell内容获取、成功捕获及进度报告等\n. 安全（加解密、信息摘要等）操作，Base64、MD5/BCrypt/AES/SHA等对称算法和RSA等非对称算法\n. Http操作，包含Get/Post/Put/Delete/Head/Options/Patch操作\n. 金额操作，金额转大写操作\n. 通用拦截器栈，前/后置、错误处理等\n. 定时器操作，定时和周期性任务\n. 常用文件操作，根据不同情况获取文件内容、Glob匹配等\n. 常用字段操作，各类字段验证、身份证提取、UUID创建等\n. 常用时间处理，常规时间格式化模板\n. 主流文件MIME整理，MIME分类\n. 服务降级处理\n. 脚本处理\n. 响应处理及分页模型\n. Tuple支持\n. GraalVM支持\n\n== 使用\n\nNOTE: 文档地址： http://gudaoxuri.github.io/dew-common/[http://gudaoxuri.github.io/dew-common/]\n\n[source,xml]\n----\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.ecfront.dew\u003c/groupId\u003e\n  \u003cartifactId\u003ecommon\u003c/artifactId\u003e\n  \u003cversion\u003e4.0.0-rc.2\u003c/version\u003e\n\u003c/dependency\u003e\n----\n\n=== Json与Java对象互转（$.json）\n\n[source,java]\n----\n// 将Json字符串转成JsonNode\nJsonNode json = $.json.toJson(\"{'name':'gudaoxuri'}\");\n// 获取json中的值\nString name = json.get(\"name\").asText();\n\n// 将Json转成Java对象\nJavaModel java = $.json.toObject(json,JavaModel.class);\n// 将Json字符串转成Java对象\njava = $.json.toObject(\"{'name':'gudaoxuri','date':'2016-07-12 12:00:00'}\", JavaModel.class);\n// 将Json字符串转成List对象\nList\u003cJavaModel\u003e javas = $.json.toList(\"[{'name':'gudaoxuri','date':'2016-07-12 12:00:00'}]\", JavaModel.class);\n\n// 将Java对象转成JsonNode\njson = $.json.toJson(java);\n// 将List对象转成JsonNode\njson = $.json.toJson(javas);\n\n// 将JsonNode转成Json字符串\nString str = $.json.toJsonString(json);\n// 将Java对象转成Json字符串\nstr = $.json.toJsonString(java);\n// 将List对象转成Json字符串\nstr = $.json.toJsonString(javas);\n\nstatic class JavaModel{\n    private String name;\n    @JsonFormat(shape=JsonFormat.Shape.STRING, pattern=\"yyyy-MM-dd HH:mm:ss\")\n    private Date date;\n    ... get/set\n}\n----\n\nTIP: 更多示例见`JsonHelperTest.java`\n\n=== Java Bean操作（$.bean）\n\n[source,java]\n----\n// Bean Copy\nUser ori = new User();\nori.setName(\"gudaoxuri\");\nUser dist = new User();\n$.bean.copyProperties(ori, dist);\n// 获取Class的注解信息（此处为IdxController类的RPC注解）\nTestAnnotation.RPC rpc = $.bean.getClassAnnotation(IdxController.class, TestAnnotation.RPC.class);\n// 获取Class的字段信息（此处为IdxController类）\nMap\u003cString, $.bean.FieldInfo\u003e fieldsInfo = $.bean.findFieldsInfo(IdxController.class, null, null, null, null);\n// 获取Class的方法信息（此处为IdxController类）\nList\u003c$.bean.MethodInfo\u003e methodsInfo = $.bean.findMethodsInfo(IdxController.class, null, null, null, null);\n// 获取字段对应的Get/Set方法（此处为User类）\nMap\u003cString, Method[]\u003e rel = $.bean.parseRelFieldAndMethod(User.class, null, null, null, null);\nUser user = new User();\nuser.setName(\"gudaoxuri\");\n// 根据字段的Get方法获取对应的值\nMap\u003cString, Object\u003e values = $.bean.findValuesByRel(user, $.bean.parseRelFieldAndMethod(User.class, null, null, null, null));\n// 获取对象所有字段的值\nvalues = $.bean.findValues(user, null, null, null, null);\n// 根据字段名称获取对应的值（需要有标准的Get方法）\nObject value = $.bean.getValue(user, \"name\");\n// 根据字段名称设置值（需要有标准的Set方法）\n$.bean.setValue(user, \"name\", \"gudaoxuri\");\n----\n\nTIP: 更多示例见`BeanHelperTest.java`\n\nNOTE: 还有一个`$.bean(boolean useCache)`方法，用于指定是否启用缓存，启用后会缓存获取过的字段和方法列表，默认启用。\n\n=== Java Class扫描操作（$.clazz）\n\n[source,java]\n----\n// 扫描获取指定包下符合条件的class类（此处要求包含Deprecated注解）\nSet\u003cClass\u003c?\u003e\u003e resultInFile = $.clazz.scan(\"com.ecfront.$.common.test\", new HashSet\u003cClass\u003c? extends Annotation\u003e\u003e(){{add(Deprecated.class);}},null);\n// 扫描获取指定包下符合条件的class类（此处要求包含Before\\\\w*类名）\nSet\u003cClass\u003c?\u003e\u003e resultInJar = $.clazz.scan(\"org.junit\",null, new HashSet\u003cString\u003e(){{add(\"Before\\\\w*\");}});\n----\n\nTIP: 更多示例见`ClassScanHelperTest.java`\n\n=== Shell脚本操作（$.shell）\n\n支持执行 ``Windows(cmd)`` 及 ``Linux(bash)`` 操作。\n\n[source,java]\n----\n// 执行命令并返回\nResp\u003cList\u003cString\u003e\u003e result = $.shell.execute(\"git remote -v\");\n\n// 执行命令并输出到报告（异步）\n$.shell.execute(\n  \"/shell-test.sh\", // 执行脚本\n  \"done!\", // 成功标识，只要捕捉到此标识就视为成功，为null时不会调用ReportHandler的success方法\n  \"step\", // 进度标识，只要捕捉到此标识就更新进度，格式为 \u003cprogressFlag\u003e空格\u003cprogress\u003e,如： progress 40，为null时不会调用ReportHandler的progress方法\n  true, // 是否返回结果（输出内容，包含标准输出stdout及错误输出stderr），为true时会返回结果到ReportHandler的complete方法中，结果暂存于内存中，对输出内容过多的脚本需要考虑占用内存的大小\n  new ReportHandler() {\n      /**\n       * 成功，在执行到successFlag时调用\n       */\n      @Override\n      void success() {\n      }\n\n      /**\n       * 失败，在发生错误时调用\n       *\n       * @param message 失败原因描述\n       */\n      @Override\n      void fail(String message) {\n      }\n\n      /**\n       * 进度回调，在执行到progressFlag且格式正确时调用\n       *\n       * @param progress 0-100\n       */\n      @Override\n      void progress(int progress) {\n      }\n\n      /**\n       * 完成，无论是否成功，在执行完成时(success 或 fail 方法后)调用\n       *\n       * @param output stdout结果\n       * @param error  stderr结果\n       */\n      @Override\n      void complete(List\u003cString\u003e output, List\u003cString\u003e error) {\n      }\n  });\n----\n\nTIP: 更多示例见`ShellHelperTest.java`\n\n=== 加解密操作（$.security）\n\n[source,java]\n----\n// 字符串 转 Base64\nString base64 = $.security.encodeStringToBase64(\"gudaoxuri\", \"UTF-8\");\n// 数组 转 Base64\nbase64 = $.security.encodeBytesToBase64(\"gudaoxuri\".getBytes());\n// Base64 转 字符串\nString str = $.security.decodeBase64ToString(base64, \"UTF-8\");\n// Base64 转 字符串\nbyte[] bytes = $.security.decodeBase64ToBytes(base64);\n\n// 摘要（此处使用SHA-256算法，支持如bcrypt SHA-X等算法）\nString digestContent = $.security.digest.digest(\"gudaoxuri\", \"SHA-256\");\n// 验证（对于bcrypt之类默认使用随机slat的加密算法必须使用此方法验证）\n$.security.digest.validate(\"gudaoxuri\", digestContent, \"SHA-256\");\n\n// 对称加密（此处使用AES算法，需要提供密码）\nString encryptContent = $.security.symmetric.encrypt(\"gudaoxuri\", \"pwd\", \"AES\");\n// 对称解密（此处使用AES算法，需要提供密码）, BadPaddingException 异常表示密码错误\n$.security.symmetric.decrypt(encryptContent, \"pwd\", \"AES\");\n\n// 非对称加密 - 生成公钥和私钥\nMap\u003cString, String\u003e keys = $.security.asymmetric.generateKeys(\"RSA\", 1024);\nString publicStr = \"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC47dAhLLB3xhDWccgEheqTbRimAhluN/ixNyYU/MvExN/bwytthiWViRV2H1sGrGr5JyH3qQSFa57jInbXD6lGN24aw2TfiejLWGkj0hMEXEtj4Bf9OuQhHUmy8unLygOuBlIhtfPLp9cSLBgVVHbt33buNTkL7fvdE2U9B3JVyQIDAQAB\";\n// 非对称加密 - 获取公钥文件\nPublicKey publicKey = $.security.asymmetric.getPublicKey(publicStr, \"RSA\");\nString privateStr = \"MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALjt0CEssHfGENZxyASF6pNtGKYCGW43+LE3JhT8y8TE39vDK22GJZWJFXYfWwasavknIfepBIVrnuMidtcPqUY3bhrDZN+J6MtYaSPSEwRcS2PgF/065CEdSbLy6cvKA64GUiG188un1xIsGBVUdu3fdu41OQvt+90TZT0HclXJAgMBAAECgYEAjXFndVhHCPU3P637PGppBqW06pREeybYUkNKH1dTS4cBaYcXmke2S290OMq2xp3tm++wbUqbKKkt97AOkWNrJfq8Ecpdw9s3c7yQGWaPuwiX38Cgtq6r0utjT20YgR6etGpqafoBt93RZpEm0eEzFPUnS7qYc86HprL0RJ0/i7kCQQDaOmvO82cYIK1ESkA0GdDVQoz2A1V8HvEWOsccRGqlWuasLUccyBnx1G/LDZUxcPOraDyxI8sdl7VbweLR0H9LAkEA2O/rWXwnSYKqdpt+OhpUBHNnMs3IMvRzefJ1zObnIMyYR3KXtpQ/fL4gEquNwJgFIaPJVg5/3zHISEw3e8XOuwJAIDrGl07tZ+vTiyVoLAmwBP8KMH83jdhIBN9zbqJQGdG+Bam+Oer3ofac+CEuapni8uq3I/ZEVj+EomOVKyWe1wJAATztROd2ee7q9h5RDBfWXughsKKH//JxLkL59R9kNkW0oMPApeQWsKmNGU4tUuoLLXP31CvlAusPz4nPzz8DvQJBAJXpICPNJw84fONzS0raRqlFoZMMI0cqeGtPIiCHKaRHyzQv/FFu2KxUcCrod8PngaBFRselzrwZILmXHqrHc1M=\";\n// 非对称加密 - 获取私钥文件\nPrivateKey privateKey = $.security.asymmetric.getPrivateKey(privateStr, \"RSA\");\n\nString d = \"Scala是一门多范式的编程语言，一种类似java的编程语言[1]  ，设计初衷是实现可伸缩的语言[2]  、并集成面向对象编程和函数式编程的各种特性。Scala是一门多范式的编程语言，一种类似java的编程语言[1]  ，设计初衷是实现可伸缩的语言[2]  、并集成面向对象编程和函数式编程的各种特性。Scala是一门多范式的编程语言，一种类似java的编程语言[1]  ，设计初衷是实现可伸缩的语言[2]  、并集成面向对象编程和函数式编程的各种特性。\";\n// 非对称加密 - 公钥加密/私钥解密\nbyte[] encryptByPub = $.security.asymmetric.encrypt(d.getBytes(\"UTF-8\"), publicKey, 1024, \"RSA\");\nString result = new String($.security.asymmetric.decrypt(encryptByPub, privateKey, 1024, \"RSA\"), \"UTF-8\");\n\n// 非对称加密 - 私钥加密/公钥解密\nbyte[] encryptByPriv = $.security.asymmetric.encrypt(d.getBytes(\"UTF-8\"), privateKey, 1024, \"RSA\");\nbyte[] decryptByPub = $.security.asymmetric.decrypt(encryptByPriv, publicKey, 1024, \"RSA\");\n$.security.asymmetric.verify(publicKey, decryptByPub,\n        $.security.asymmetric.sign(privateKey, d.getBytes(\"UTF-8\"), \"SHA1withRSA\"),\n        \"SHA1withRSA\");\n----\n\nTIP: 更多示例见`SecurityHelperTest.java`\n\n=== Http操作（$.http）\n\n[source,java]\n----\n// get\nString result = $.http.get(\"https://httpbin.org/get\");\n// get 带 head\nresult = $.http.get(\"https://httpbin.org/get\", new HashMap\u003cString, String\u003e() {{\n    put(\"Customer-A\", \"AAA\");\n    put(\"Accept\", \"json\");\n}});\n// get 包含 head、Content-Type、编码、超时等信息\nresult = $.http.get(\"https://httpbin.org/get\", new HashMap\u003cString, String\u003e() {{\n    put(\"Customer-A\", \"AAA\");\n    put(\"Accept\", \"json\");\n}}, \"application/json; charset=utf-8\", \"utf-8\", 5000, 5000);\n// delete\nresult = $.http.delete(\"https://httpbin.org/delete\");\nAssert.assertEquals(\"httpbin.org\", $.json.toJson(result).get(\"headers\").get(\"Host\").asText());\n// post - data\nresult = $.http.post(\"https://httpbin.org/post\", \"some data\");\n// post - form\nresult = $.http.post(\"https://httpbin.org/post\", new HashMap\u003cString, Object\u003e() {{\n    put(\"a\", \"1\");\n}}, \"application/x-www-form-urlencoded\");\n// post - file\nresult = $.http.post(\"https://httpbin.org/post\", new File(this.getClass().getResource(\"/\").getPath() + \"conf1.json\"));\n// put - data\nresult = $.http.put(\"https://httpbin.org/put\", \"some data\");\n// put - form\nresult = $.http.put(\"https://httpbin.org/put\", new HashMap\u003cString, Object\u003e() {{\n    put(\"a\", \"1\");\n}}, \"application/x-www-form-urlencoded\");\n// put - file\nresult = $.http.put(\"https://httpbin.org/put\", new File(this.getClass().getResource(\"/\").getPath() + \"conf1.json\"));\n// put 返回带 head的内容，同样还有getWithHead、postWithHead、deleteWtihHead\nHttpHelper.WrapHead responseWrap = $.http.putWithHead(\"https://httpbin.org/put\", new File(this.getClass().getResource(\"/\").getPath() + \"conf1.json\"));\n// head\nMap\u003cString, String\u003e head = $.http.head(\"https://httpbin.org/get\");\n// options\nhead = $.http.options(\"https://httpbin.org/get\");\n----\n\nTIP: 更多示例见`HttpHelperTest.java`\n\nNOTE: GET POST PUT DELETE 都带 `Wrap`方法，返回包含扩展信息的数据，比如 `getWrap`\n\nNOTE: 还有一个`$.http(int maxTotal, int maxPerRoute, int defaultConnectTimeoutMS, int defaultSocketTimeoutMS, boolean retryAble)`方法，用于指定`整个连接池最大连接数`及`每个路由（域）的默认最大连接`，`$.http`是`$.http(200,20)`的语法糖。\n\n=== 通用拦截器栈（$.interceptor）\n\n[source,java]\n----\n// 没有注册拦截器的情况\nResp\u003cDewInterceptContext\u003cObj, Obj\u003e\u003e resp =\n        $.interceptor.process(\"none\", new Obj(\"1\"), new HashMap\u003c\u003e(), context -\u003e {\n            try {\n                // 业务逻辑，只做简单将input对象copy到output对象\n                context.setOutput($.bean.copyProperties(context.getInput(), Obj.class));\n                return Resp.success(context);\n            } catch (InvocationTargetException | IllegalAccessException | InstantiationException e) {\n                e.printStackTrace();\n                return Resp.serverError(\"\");\n            }\n        });\nAssert.assertTrue(resp.ok());\nAssert.assertEquals(\"1\", resp.getBody().getOutput().getF());\n// 注册了一个拦截器A\n$.interceptor.register(\"test\", new InterceptorA());\nresp = $.interceptor.process(\"test\", new Obj(\"1\"), new HashMap\u003c\u003e(), context -\u003e {\n    ... 同上，只做简单将input对象copy到output对象\n});\nAssert.assertTrue(resp.ok());\nAssert.assertEquals(\"2\", resp.getBody().getInput().getF());\nAssert.assertEquals(\"3\", resp.getBody().getOutput().getF());\n// 注册了另一个拦截器B，假设B执行会报错\n$.interceptor.register(\"test\", new InterceptorB());\nresp = $.interceptor.process(\"test\", new Obj(\"11\"), new HashMap\u003c\u003e(), context -\u003e {\n    ... 同上，只做简单将input对象copy到output对象\n});\nAssert.assertTrue(!resp.ok());\n----\n\nTIP: 更多示例见`InterceptorTest.java`\n\n=== 定时器操作（$.timer）\n\n[source,java]\n----\n// 延迟任务\n$.timer.timer(1, () -\u003e // Do Something);\n// 周期性任务，参数 fixedRate 为true时表示每periodSec执行，为false表示fixedDelay，表示在当前任务执行完成后过periodSec再执行\nString taskId = $.timer.periodic(1, true, () -\u003e // Do Something);\n// 取消周期性任务\n$.timer.cancel(taskId);\n----\n\nTIP: 更多示例见`TimerHelperTest.java`\n\n=== 常用文件操作（$.file）\n\n[source,java]\n----\n// 根据classpath读取文件所有内容（jar包外路径优先），另外readAllByPath、readAllByFile、readAllByPathName等衍生方法\nString conf=$.file.readAllByClassPath(\"conf1.json\",\"UTF-8\");\n----\n\nTIP: 更多示例见`FileHelperTest.java`\n\n=== 常用金额操作（$.amount）\n\n[source,java]\n----\n// 转换成中文大写:壹仟贰佰叁拾肆亿伍仟陆佰柒拾捌万玖仟零壹拾贰元叁角肆分\n$.amount.convert(\"1234,5678,9012.34\");\n----\n\nTIP: 更多示例见`AmountHelperTest.java`\n\n=== 常用字段操作（$.field）\n\n[source,java]\n----\n// 验证邮箱格式是否合法\n$.field.validateEmail(\"i@sunisle.org\");\n// 验证手机号格式是否合法\n$.field.validateMobile(\"18657120000\");\n// 是否是汉字\n$.field.isChinese(\"孤岛旭日\");\n// 验证身份证是否合法\n$.field.validateIdNumber(\"330102199901015759\");\n// 根据身份编号获取年龄\n$.field.getAgeByIdCard(\"330102199901015759\");\n// 根据身份编号获取生日\n$.field.getBirthByIdCard(\"330102199901015759\");\n// 根据身份编号获取生日年\n$.field.getYearByIdCard(\"330102199901015759\");\n// 根据身份编号获取生日月\n$.field.getMonthByIdCard(\"330102199901015759\");\n// 根据身份编号获取生日天\n$.field.getDateByIdCard(\"330102199901015759\");\n// 根据身份编号获取性别\n$.field.getGenderByIdCard(\"330102199901015759\");\n// 根据身份编号获取户籍省份\n$.field.getProvinceByIdCard(\"330102199901015759\");\n----\n\nTIP: 更多示例见`FieldHelperTest.java`\n\n=== 服务降级处理（$.fallback）\n\n[source,java]\n----\n\n// ===========================================\n// =============== 降级核心方法 ===============\n// ===========================================\n\n/**\n* 根据组名获取降级信息\n*\n* @param groupName 组名，全局唯一\n* @return 降级信息\n*/\n$.fallback.getFallbackInfo(String groupName)\n\n/**\n * 带降级的处理方法\n *\n * @param groupName       组名，全局唯一\n * @param normalProcessor 正常方法，抛异常时进入失败方法\n * @param errorProcessor  失败方法\n */\n$.fallback.execute(String groupName, NormalProcessor normalProcessor, ErrorProcessor errorProcessor)\n\n/**\n * 带降级的处理方法\n *\n * @param groupName        组名，全局唯一\n * @param normalProcessor  正常方法，抛异常时进入失败方法\n * @param errorProcessor   失败方法\n * @param fallbackStrategy 降级策略\n */\n$.fallback.execute(String groupName, NormalProcessor normalProcessor, ErrorProcessor errorProcessor,\n                     FallbackStrategy fallbackStrategy)\n\n/**\n * 带降级的处理方法\n *\n * @param groupName             组名，全局唯一\n * @param normalProcessor       正常方法，抛异常时进入失败方法\n * @param errorProcessor        失败方法\n * @param excludeFallbackErrors 不做降级处理的异常集合（视为业务上正常的错误）\n */\n$.fallback.execute(String groupName, NormalProcessor normalProcessor, ErrorProcessor errorProcessor,\n                     Class\u003c? extends Throwable\u003e... excludeFallbackErrors)\n\n/**\n * 带降级的处理方法\n *\n * @param groupName             组名，全局唯一\n * @param normalProcessor       正常方法，抛异常时进入失败方法\n * @param errorProcessor        失败方法\n * @param fallbackStrategy      降级策略\n * @param excludeFallbackErrors 不做降级处理的异常集合（视为业务上正常的错误）\n */\n$.fallback.execute(String groupName, NormalProcessor normalProcessor, ErrorProcessor errorProcessor,\n                         FallbackStrategy fallbackStrategy, Class\u003c? extends Throwable\u003e... excludeFallbackErrors)\n\n// ===========================================\n// ================= 使用示例 =================\n// ===========================================\n$.fallback.execute(\"testGetUser\",\n                this::getUserNormal,\n                this::getUserError);\n\nString getUserNormal() throws Exception {\n    // 正常处理方法，或抛出异常\n    throw new NotFoundException(\"Not Found xxx\");\n}\n\nString getUserError(Throwable e, FallbackHelper.FallbackInfo fallbackInfo) {\n    // 错误处理方法，降级处理\n    return \"-1\";\n}\n----\n\nTIP: 更多示例见`FallbackHelperTest.java`\n\n=== 脚本操作（$.script）\n\n[source,java]\n----\n/**\n * 脚本处理，包含预编译，适用于脚本复用性的场景\n *\n * @param jsFunsCode    JS 脚本\n * @param addCommonCode 是否添加dew-common包到脚本\n */\npublic static ScriptHelper script(String jsFunsCode, boolean addCommonCode) throws ScriptException {\n    return ScriptHelper.build(jsFunsCode, addCommonCode);\n}\n\n/**\n * 脚本处理，包含预编译，适用于脚本复用性的场景，默认添加dew-common包到脚本\n *\n * @param jsFunsCode JS 脚本\n */\npublic static ScriptHelper script(String jsFunsCode) throws ScriptException {\n    return ScriptHelper.build(jsFunsCode, true);\n}\n\n/**\n * 脚本处理，适用于简单的脚本的执行\n *\n * @param jsCode JS 脚本\n */\npublic static Object eval(String jsCode) throws ScriptException {\n    return ScriptHelper.eval(jsCode);\n}\n----\n\n[source,java]\n.脚本处理示例\n----\nScriptHelper s1 = $.script(\"function fun1(param){return param;}\");\nAssert.assertEquals(\"hi\", s1.execute(\"fun1\", \"hi\"));\n\nScriptHelper s2 = $.script(\"function fun2(D){\\r\\n\" +\n        \" var data = JSON.parse(D);\\n\" +\n        \" return $.field.getGenderByIdCard(data.idcard);\\n\" +\n        \"}\");\nAssert.assertEquals(\"M\", s2.execute(\"fun2\", \"{\\\"idcard\\\":\\\"110101201604016117\\\"}\"));\n\nAssert.assertEquals(10240, $.eval( \"1024*10\"));\n----\n\n=== 响应处理模型（Resp）\n\n[NOTE]\n====\n响应模型，用于统一请求响应处理，模型由三个属性组成：\n. code：响应编码，同HTTP状态码，200表示成功\n. message：错误描述，当code不为200时用于描述错误信息\n. body：返回的实际对象\n====\n\n[source,java]\n----\n/**\n * 返回是否成功\n */\npublic boolean ok();\n\n/**\n * 返回成功\n *\n * @param body 实际对象\n */\npublic static \u003cE\u003e Resp\u003cE\u003e success(E body);\n\n/**\n * 返回未找到资源的错误，如数据记录不存在\n *\n * @param message 错误描述\n */\npublic static \u003cE\u003e Resp\u003cE\u003e notFound(String message);\n\n/**\n * 返回资源冲突的错误，如密码错误\n *\n * @param message 错误描述\n */\npublic static \u003cE\u003e Resp\u003cE\u003e conflict(String message);\n\n/**\n * 返回资源被锁定的错误，如当前用户被禁用\n *\n * @param message 错误描述\n */\npublic static \u003cE\u003e Resp\u003cE\u003e locked(String message);\n\n/**\n * 返回请求格式的错误，如json不合法\n *\n * @param message 错误描述\n */\npublic static \u003cE\u003e Resp\u003cE\u003e unsupportedMediaType(String message);\n\n/**\n * 返回请求参数的错误，如缺少参数\n *\n * @param message 错误描述\n */\npublic static \u003cE\u003e Resp\u003cE\u003e badRequest(String message);\n\n/**\n * 返回请求拒绝的错误\n *\n * @param message 错误描述\n */\npublic static \u003cE\u003e Resp\u003cE\u003e forbidden(String message);\n\n/**\n * 返回未认证的错误，如资源没有权限访问\n *\n * @param message 错误描述\n */\npublic static \u003cE\u003e Resp\u003cE\u003e unAuthorized(String message);\n\n/**\n * 返回服务器的错误，如捕捉到执行异常\n *\n * @param message 错误描述\n */\npublic static \u003cE\u003e Resp\u003cE\u003e serverError(String message);\n\n/**\n * 返回方法未实现的错误\n *\n * @param message 错误描述\n */\npublic static \u003cE\u003e Resp\u003cE\u003e notImplemented(String message);\n\n/**\n * 返回服务不可用的错误\n *\n * @param message 错误描述\n */\npublic static \u003cE\u003e Resp\u003cE\u003e serverUnavailable(String message);\n\n/**\n * 返回未知错误\n *\n * @param message 错误描述\n */\npublic static \u003cE\u003e Resp\u003cE\u003e unknown(String message);\n\n/**\n * 返回自定义错误\n *\n * @param message 错误描述\n */\npublic static \u003cE\u003e Resp\u003cE\u003e customFail(String code, String message);\n\n/**\n * 错误转换，解决java泛型继承问题\n *\n * @param resp 原响应对象\n * @return 转换后的响应对象\n */\npublic static Resp\u003cVoid\u003e error(Resp\u003c?\u003e resp);\n\n/**\n * 响应body转换，将body类型A转换成类型B\n *\n * @param resp      源响应\n * @param bodyClazz 目标body类型\n * @return 目标响应\n */\npublic static \u003cE\u003e Resp\u003cE\u003e generic(Resp resp, Class\u003cE\u003e bodyClazz);\n\n/**\n * 响应body转换(列表)，将body类型A转换成类型B\n *\n * @param resp      源响应\n * @param bodyClazz 目标body类型\n * @return 目标响应\n */\npublic static \u003cE\u003e Resp\u003cList\u003cE\u003e\u003e genericList(Resp resp, Class\u003cE\u003e bodyClazz);\n\n    /**\n     * 响应body转换(Set)，将body类型A转换成类型B\n     *\n     * @param resp      源响应\n     * @param bodyClazz 目标body类型\n     * @return 目标响应\n     */\n    public static \u003cE\u003e Resp\u003cSet\u003cE\u003e\u003e genericSet(String resp, Class\u003cE\u003e bodyClazz);\n\n/**\n * 响应body转换(分页)，将body类型A转换成类型B\n *\n * @param resp      源响应\n * @param bodyClazz 目标body类型\n * @return 目标响应\n */\npublic static \u003cE\u003e Resp\u003cPageDTO\u003cE\u003e\u003e genericPage(Resp resp, Class\u003cE\u003e bodyClazz);\n----\n\n=== 分页模型（Page）\n\n[NOTE]\n====\n响应模型，用于统一请求响应处理，模型由三个属性组成：\n. code：响应编码，同HTTP状态码，200表示成功\n. message：错误描述，当code不为200时用于描述错误信息\n. body：返回的实际对象\n====\n\n[source,java]\n----\n/**\n * 当前页，从1开始\n */\nprivate long pageNumber;\n/**\n * 每页记录数\n */\nprivate long pageSize;\n/**\n * 总页数\n */\nprivate long pageTotal;\n/**\n * 总记录数\n */\nprivate long recordTotal;\n/**\n * 实际对象\n */\nprivate List\u003cE\u003e objects;\n----\n\n== 功能禁用\n\n如果不需要某些功能可以在maven中排除以减少包体积\n\n[source,xml]\n----\n\u003c!--$.json dependency begin--\u003e\n\u003cexclusion\u003e\n    \u003cgroupId\u003ecom.fasterxml.jackson.core\u003c/groupId\u003e\n    \u003cartifactId\u003ejackson-databind\u003c/artifactId\u003e\n\u003c/exclusion\u003e\n\u003c!--$.json dependency end--\u003e\n\u003c!--$.bean dependency begin--\u003e\n\u003cexclusion\u003e\n    \u003cgroupId\u003ecommons-beanutils\u003c/groupId\u003e\n    \u003cartifactId\u003ecommons-beanutils\u003c/artifactId\u003e\n\u003c/exclusion\u003e\n\u003c!--$.bean dependency end--\u003e\n\u003c!--$.security dependency begin--\u003e\n\u003cexclusion\u003e\n    \u003cgroupId\u003eorg.mindrot\u003c/groupId\u003e\n    \u003cartifactId\u003ejbcrypt\u003c/artifactId\u003e\n\u003c/exclusion\u003e\n\u003c!--$.security dependency end--\u003e\n\u003c!--$.http dependency begin--\u003e\n\u003cexclusion\u003e\n    \u003cgroupId\u003eorg.apache.httpcomponents\u003c/groupId\u003e\n    \u003cartifactId\u003ehttpclient\u003c/artifactId\u003e\n\u003c/exclusion\u003e\n\u003cexclusion\u003e\n    \u003cgroupId\u003eorg.apache.httpcomponents\u003c/groupId\u003e\n    \u003cartifactId\u003ehttpmime\u003c/artifactId\u003e\n\u003c/exclusion\u003e\n\u003cexclusion\u003e\n    \u003cgroupId\u003eorg.jooq\u003c/groupId\u003e\n    \u003cartifactId\u003ejoox\u003c/artifactId\u003e\n\u003c/exclusion\u003e\n\u003c!--$.http dependency end--\u003e\n----\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgudaoxuri%2Fdew-common","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgudaoxuri%2Fdew-common","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgudaoxuri%2Fdew-common/lists"}