{"id":13848479,"url":"https://github.com/Dreampie/Resty","last_synced_at":"2025-07-12T13:31:10.305Z","repository":{"id":25166053,"uuid":"28589035","full_name":"Dreampie/Resty","owner":"Dreampie","description":"The minimalist framework of RESTful(server and client) - Resty","archived":false,"fork":false,"pushed_at":"2021-11-05T02:19:42.000Z","size":1953,"stargazers_count":1247,"open_issues_count":5,"forks_count":430,"subscribers_count":212,"default_branch":"master","last_synced_at":"2024-11-12T11:50:27.621Z","etag":null,"topics":["activerecord","httpclient","java","restful","server","web"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Dreampie.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-12-29T10:45:13.000Z","updated_at":"2024-10-25T08:30:42.000Z","dependencies_parsed_at":"2022-08-23T22:00:39.341Z","dependency_job_id":null,"html_url":"https://github.com/Dreampie/Resty","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dreampie%2FResty","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dreampie%2FResty/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dreampie%2FResty/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dreampie%2FResty/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Dreampie","download_url":"https://codeload.github.com/Dreampie/Resty/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225802673,"owners_count":17526452,"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":["activerecord","httpclient","java","restful","server","web"],"created_at":"2024-08-04T19:00:50.318Z","updated_at":"2024-11-22T00:30:26.323Z","avatar_url":"https://github.com/Dreampie.png","language":"Java","funding_links":[],"categories":["Java","开发框架"],"sub_categories":[],"readme":"\nResty 一款极简的restful轻量级的web框架\n===========\n\n更新说明\n\n----\n\n- [x] feature/20170203 强化Stringer工具和让日志支持彩色输出方便开发者调试 [@t-baby](https://github.com/t-baby)\n\n----\n\n[![Join the chat at https://gitter.im/Dreampie/Resty](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Dreampie/Resty?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge) \n[![Issue Stats](http://issuestats.com/github/Dreampie/Resty/badge/pr?style=flat)](http://issuestats.com/github/Dreampie/Resty) \n[![Issue Stats](http://issuestats.com/github/Dreampie/Resty/badge/issue?style=flat)](http://issuestats.com/github/Dreampie/Resty)\n\u003ca href=\"http://dreampie.gitbooks.io/resty-chs/content/index.html\" target=\"_blank\"\u003e开发文档\u003c/a\u003e\n\n如果你还不是很了解restful，或者认为restful只是一种规范不具有实际意义，推荐一篇osc两年前的文章：[RESTful API 设计最佳实践](http://www.oschina.net/translate/best-practices-for-a-pragmatic-restful-api)  和 Infoq的一篇极其理论的文章  [理解本真的REST架构风格](http://www.infoq.com/cn/articles/understanding-restful-style) 虽然有点老，介绍的也很简单，大家权当了解，restful的更多好处，还请google\n\n拥有jfinal/activejdbc一样的activerecord的简洁设计，使用更简单的restful框架\n\nrestful的api设计，是作为restful的服务端最佳选择（使用场景：客户端和服务端解藕，用于对静态的html客户端（mvvm等），ios，andriod等提供服务端的api接口）\n\nJava开发指南:[Java style guide](https://github.com/Dreampie/java-style-guide)\n\nApi设计指南:[Http api design](https://github.com/Dreampie/http-api-design-ZH_CN)\n\nResty例子： [resty-samples](https://github.com/Dreampie/resty-samples)(纯接口) [resty-demo](https://github.com/Dreampie/resty-demo)(带界面)\n\n如果你在考虑前后端分离方案，推荐resty+vuejs，https://github.com/Dreampie/vuejs2-demo\n\n开发群: \u003ca target=\"_blank\" href=\"http://shang.qq.com/wpa/qunwpa?idkey=8fc9498714ebbc3675cc5a5035858004154ef4645ebc9c128dfd76688d32179b\"\u003e\u003cimg border=\"0\" src=\"http://pub.idqqimg.com/wpa/images/group.png\" alt=\"极简Restful框架 - Resty\" title=\"极简Restful框架 - Resty\"\u003e\u003c/a\u003e\n\n其他开发者贡献的插件:[Beetl扩展(大鹏)](https://github.com/zhaopengme/Resty-ext)  [Shiro扩展(zhoulieqing)](http://git.oschina.net/zhoulieqing/resty-shiro)\n[MongoPlugin(T-baby)](https://github.com/T-baby/MongoDB-Plugin)\n\n\n\u003e 有兴趣一起维护该框架的，可以联系我，进入合作开发\n\n\u003e 规范：提前说明功能，新建分支 `feature/日期` 功能 `fix/日期` 修复 在readme里添加一个TODO list描述\n\n\u003e - [x] feature/20161228 a task list item done [@Dreampie](https://github.com/Dreampie)\n\n\u003e - [ ] feature/20161229 a task list item todo [@Dreampie](https://github.com/Dreampie)\n\n\u003e 注意代码2格缩进，最后所有合作者一起代码review，合格之后合并到master\n\nmaven使用方式：\n\n1. 添加依赖包\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecn.dreampie\u003c/groupId\u003e\n    \u003cartifactId\u003eresty-route\u003c/artifactId\u003e\n    \u003cversion\u003e1.3.1.SNAPSHOT\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n2.如果使用带有SNAPSHOT后缀的包，请添加该仓库\n```xml\n\u003crepositories\u003e\n    \u003crepository\u003e\n      \u003cid\u003eoss-snapshots\u003c/id\u003e\n      \u003curl\u003ehttps://oss.sonatype.org/content/repositories/snapshots\u003c/url\u003e\n      \u003creleases\u003e\n        \u003cenabled\u003etrue\u003c/enabled\u003e\n      \u003c/releases\u003e\n      \u003csnapshots\u003e\n        \u003cenabled\u003etrue\u003c/enabled\u003e\n      \u003c/snapshots\u003e\n    \u003c/repository\u003e\n  \u003c/repositories\u003e\n```\n\n一、独有优点：\n-----------\n\n重大更新：\n\n1.3.0更新内容： 使用jetty作为嵌入式热加载默认实现(只要java文件进行编译就会重新加载)，resty-captcha验证码功能...\n\n1.2.0更新内容：使用header来控制api版本，基于数据源的读写分离，更简单的tableSetting.[详情查看](http://www.oschina.net/news/68791/resty-1-2-0-snapshot)\n\n1.1.0版本重大更新：快速接入spring，缓存，加密，header，XForwardedSupports等，[详情查看](http://www.oschina.net/news/67001/resty-1-1-0-snapshot)\n\n\nRecord的时代已经到来，你完全不用使用任何的model来执行你的数据\n```java\n//创建record的执行器  针对sec_user表 并开启缓存\nRecord recordDAO = new Record(\"sec_user\");\n//使用当前数据源和表数据 new一个对象来保存数据\nrecordDAO.reNew().set(\"属性\", \"值\").save();\nRecord r1 = recordDAO.reNew().set(\"属性\", \"值\");\nRecord r2 = recordDAO.reNew().set(\"属性\", \"值\");\n//批量保存\nrecordDAO.save(r1, r2);\n//更新\nr2.set(\"属性\", \"值\").update()\n//查询全部\nList\u003cRecord\u003e records = recordDAO.findAll();\n//条件查询\nrecordDAO.findBy(where,paras)\n//分页查询\nPage\u003cRecord\u003e records = recordDAO.paginateAll();\n//根据id删除\nrecordDAO.deleteById(\"1\");\n\n//本次查询放弃使用cache \nrecordDAO.unCache().findBy(where,paras);\n//把record的数据源切换到dsmName数据源上\nrecordDAO.useDS(dsmName).findBy(where,paras);\n\n//等等，完全摆脱model，实现快速操作数据\n\n```\n\nModel支持动态切换数据源和本次查询放弃使用cache\n```java\nUser dao=new User();\n//本次查询放弃使用cache \ndao.unCache().findBy(where,paras);\n//把model的数据源切换到dsmName数据源上\ndao.useDS(dsmName).findBy(where,paras);\n\n```\n\n\n//数据库和全局参数配置移植到application.properties  详情参看resty-example\n\n```java\n#not must auto load\napp.encoding=UTF-8\napp.devEnable=true\napp.showRoute=false\napp.cacheEnabled=true\n#默认使用ehcacheProvider\n#app.cacheProvider=cn.dreampie.cache.redis.RedisProvider\n\n##druid plugin auto load\ndb.default.url=jdbc:mysql://127.0.0.1/example?useUnicode=true\u0026characterEncoding=UTF-8\ndb.default.user=dev\ndb.default.password=dev1010\ndb.default.dialect=mysql\n\n#c3p0配置\nc3p0.default.minPoolSize=3\nc3p0.default.maxPoolSize=20\n\n#druid配置\n#druid.default.initialSize=10\n#druid.default.maxPoolPreparedStatementPerConnectionSize=20\n#druid.default.timeBetweenConnectErrorMillis=1000\n#druid.default.filters=slf4j,stat,wall\n\n#flyway database migration auto load\nflyway.default.valid.clean=true\nflyway.default.migration.auto=true\nflyway.default.migration.initOnMigrate=true\n\n\ndb.demo.url=jdbc:mysql://127.0.0.1/demo?useUnicode=true\u0026characterEncoding=UTF-8\ndb.demo.user=dev\ndb.demo.password=dev1010\ndb.demo.dialect=mysql\n#druid\ndruid.demo.initialSize=10\ndruid.demo.maxPoolPreparedStatementPerConnectionSize=20\ndruid.demo.timeBetweenConnectErrorMillis=1000\ndruid.demo.filters=slf4j,stat,wall\n#flyway\nflyway.demo.valid.clean=true\nflyway.demo.migration.auto=true\nflyway.demo.migration.initOnMigrate=true\n\n\n\n//数据库的配置精简  自动从文件读取参数  只需配置model扫描目录 和dsmName\npublic void configPlugin(PluginLoader pluginLoader) {\n  //第一个数据库\n  ActiveRecordPlugin activeRecordPlugin = new ActiveRecordPlugin(new DruidDataSourceProvider(\"default\"), true);\n  activeRecordPlugin.addIncludePaths(\"cn.dreampie.resource\");\n  pluginLoader.add(activeRecordPlugin);\n}\n\n```\n\n\n\n1.极简的route设计，完全融入普通方法的方式，方法参数就是请求参数，方法返回值就是数据返回值\n\n```java\n  @GET(\"/users/:name\")\n  //在路径中自定义解析的参数 如果有其他符合 也可以用 /users/{name}\n  // 参数名就是方法变量名  除路径参数之外的参数也可以放在方法参数里  传递方式 user={json字符串}\n  public Map find(String name,User user) {\n    // return Lister.of(name);\n    return Maper.of(\"k1\", \"v1,name:\" + name, \"k2\", \"v2\");\n    //返回什么数据直接return\n  }\n```\n\n2.极简的activerecord设计，数据操作只需短短的一行,支持批量保存对象\n\n```java\n  //批量保存\n  User u1 = new User().set(\"username\", \"test\").set(\"providername\", \"test\").set(\"password\", \"123456\");\n  User u2 = new User().set(\"username\", \"test\").set(\"providername\", \"test\").set(\"password\", \"123456\");\n  User.dao.save(u1,u2);\n\n  //普通保存\n  User u = new User().set(\"username\", \"test\").set(\"providername\", \"test\").set(\"password\", \"123456\");\n  u.save();\n\n  //更新\n  u.update();\n  //条件更新\n  User.dao.updateBy(columns,where,paras);\n  User.dao.updateAll(columns,paras);\n\n  //删除\n  u.deleted();\n  //条件删除\n  User.dao.deleteBy(where,paras);\n  User.dao.deleteAll();\n\n  //查询\n  User.dao.findById(id);\n  User.dao.findBy(where,paras);\n  User.dao.findAll();\n\n  //分页\n  User.dao.paginateBy(pageNumber,pageSize,where,paras);\n  User.dao.paginateAll(pageNumber,pageSize);\n```\n\n3.极简的客户端设计，支持各种请求，文件上传和文件下载（支持断点续传）\n\n```java\n  Client httpClient=null;//创建客户端对象\n  //启动resty-example项目，即可测试客户端\n  String apiUrl = \"http://localhost:8081/api/v1.0\";\n  //如果不需要 使用账号登陆\n  //httpClient = new Client(apiUrl);\n  //如果有账号权限限制  需要登陆\n  httpClient = new Client(apiUrl, \"/tests/login\", \"u\", \"123\");\n\n  //该请求必须  登陆之后才能访问  未登录时返回 401  未认证\n  ClientRequest authRequest = new ClientRequest(\"/users\");\n  ClientResult authResult = httpClient.build(authRequest).get();\n  System.out.println(authResult.getResult());\n\n  //get\n  ClientRequest getRequest = new ClientRequest(\"/tests\");\n  ClientResult getResult = httpClient.build(getRequest).get();\n  System.out.println(getResult.getResult());\n\n  //post\n  ClientRequest postRequest = new ClientRequest(\"/tests\");\n  postRequest.addParam(\"test\", Jsoner.toJSONString(Maper.of(\"a\", \"谔谔\")));\n  ClientResult postResult = httpClient.build(postRequest).post();\n  System.out.println(postResult.getResult());\n\n  //put\n  ClientRequest putRequest = new ClientRequest(\"/tests/x\");\n  ClientResult putResult = httpClient.build(putRequest).put();\n  System.out.println(putResult.getResult());\n\n\n  //delete\n  ClientRequest deleteRequest = new ClientRequest(\"/tests/a\");\n  ClientResult deleteResult = httpClient.build(deleteRequest).delete();\n  System.out.println(deleteResult.getResult());\n\n\n  //upload\n  ClientRequest uploadRequest = new ClientRequest(\"/tests/resty\");\n  uploadRequest.addUploadFiles(\"resty\", ClientTest.class.getResource(\"/resty.jar\").getFile());\n  uploadRequest.addParam(\"des\", \"test file  paras  测试笔\");\n  ClientResult uploadResult = httpClient.build(uploadRequest).post();\n  System.out.println(uploadResult.getResult());\n\n\n  //download  支持断点续传\n  ClientRequest downloadRequest = new ClientRequest(\"/tests/file\");\n  downloadRequest.setDownloadFile(ClientTest.class.getResource(\"/resty.jar\").getFile().replace(\".jar\", \"x.jar\"));\n  ClientResult downloadResult = httpClient.build(downloadRequest).get();\n  System.out.println(downloadResult.getResult());\n```\n\n\n4.支持多数据源和嵌套事务（使用场景：需要访问多个数据库的应用，或者作为公司内部的数据中间件向客户端提供数据访问api等）\n\n```java\n  // 在resource里使用事务,也就是controller里，rest的世界认为所以的请求都表示资源，所以这儿叫resource\n  @GET(\"/users\")\n  @Transaction(name = {\"default\", \"demo\"}) //多数据源的事务，如果你只有一个数据库  直接@Transaction 不需要参数\n  public User transaction() {\n  //TODO 用model执行数据库的操作  只要有操作抛出异常  两个数据源 都会回滚  虽然不是分布式事务  也能保证代码块的数据执行安全\n  }\n\n  // 如果你需要在service里实现事务，通过java动态代理（必须使用接口，jdk设计就是这样）\n  public interface UserService {\n    @Transaction(name = {\"demo\"})//service里添加多数据源的事务，如果你只有一个数据库  直接@Transaction 不需要参数\n    public User save(User u);\n  }\n  // 在resource里使用service层的 事务\n  // @Transaction(name = {\"demo\"})的注解需要写在service的接口上\n  // 注意java的自动代理必须存在接口\n  // TransactionAspect 是事务切面 ，你也可以实现自己的切面比如日志的Aspect，实现Aspect接口\n  // 再private UserService userService = AspectFactory.newInstance(new UserServiceImpl(), new TransactionAspect(),new LogAspect());\n  private UserService userService = AspectFactory.newInstance(new UserServiceImpl(), new TransactionAspect());\n```\n\n5.极简的权限设计,可以通过cache支持分布式session，你只需要实现一个简单接口和添加一个拦截器，即可实现基于url的权限设计\n\n```java\n  public void configInterceptor(InterceptorLoader interceptorLoader) {\n    //权限拦截器 放在第一位 第一时间判断 避免执行不必要的代码\n    interceptorLoader.add(new SecurityInterceptor(new MyAuthenticateService()));\n  }\n\n  //实现接口\n  public class MyAuthenticateService implements AuthenticateService {\n    //登陆时 通过name获取用户的密码和权限信息\n    public Principal findByName(String name) {\n      DefaultPasswordService defaultPasswordService = new DefaultPasswordService();\n\n      Principal principal = new Principal(name, defaultPasswordService.hash(\"123\"), new HashSet\u003cString\u003e() {{\n        add(\"api\");\n      }});\n      return principal;\n    }\n    //基础的权限总表  所以的url权限都放在这儿  你可以通过 文件或者数据库或者直接代码 来设置所有权限\n    public Set\u003cCredential\u003e loadAllCredentials() {\n      Set\u003cCredential\u003e credentials = new HashSet\u003cCredential\u003e();\n      credentials.add(new Credential(\"GET\", \"/api/v1.0/users**\", \"users\"));\n      return credentials;\n    }\n  }\n```\n\n6.极简的缓存设计，可扩展，非常简单即可启用model的自动缓存功能\n\n```java\n  //启用缓存并在要自动使用缓存的model上\n  //config application.properties  app.cacheEnabled=true\n  //开启缓存@Table(name = \"sec_user\", cached = true)\n\n  @Table(name = \"sec_user\", cached = true)\n  public class User extends Model\u003cUser\u003e {\n    public static User dao = new User();\n\n  }\n```\n\n7.下载文件，只需要直接return file\n\n```java\n  @GET(\"/files\")\n  public File file() {\n    return new File(path);\n  }\n```\n\n8.上传文件，注解配置把文件写到服务器\n\n```java\n  @POST(\"/files\")\n  @FILE(dir = \"/upload/\") //配置上传文件的相关信息\n  public UploadedFile file(UploadedFile file) {\n    return file;\n  }\n```\n\n9.当然也是支持传统的web开发，你可以自己实现数据解析，在config里添加自定义的解析模板\n\n```java\n  public void configConstant(ConstantLoader constantLoader) {\n    // 通过后缀来返回不同的数据类型  你可以自定义自己的  render  如：FreemarkerRender\n    //默认已添加json和text的支持，只需要把自定义的Render add即可\n    // constantLoader.addRender(\"json\", new JsonRender());\n  }\n```\n\n二、运行example示例：\n-----------------\n\n1.在本地mysql数据库里创建demo,example数据库，对应application.properties的数据库配置\n\n2.运行resty-example下的pom.xml-\u003eflyway-maven-plugin:migrate，自动根具resources下db目录下的数据库文件生成数据库表结构\n\n3.运行resty-example下的pom.xml-\u003etomcat6-maven-plugin:run,启动example程序\n\n提醒:推荐idea作为开发ide，使用分模块的多module开发\n\nLicense \u003ca href=\"https://www.apache.org/licenses/LICENSE-2.0\" target=\"_blank\"\u003eApache License V2\u003c/a\u003e\n\n捐赠：\n[支付宝](https://raw.githubusercontent.com/Dreampie/Resty/master/alipay.png)\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDreampie%2FResty","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDreampie%2FResty","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDreampie%2FResty/lists"}