{"id":15037840,"url":"https://github.com/troyzhxu/bean-searcher","last_synced_at":"2026-05-13T04:01:12.562Z","repository":{"id":37431872,"uuid":"94215190","full_name":"troyzhxu/bean-searcher","owner":"troyzhxu","description":"🔥🔥🔥 A read-only ORM focusing on advanced query, naturally supports joined tables, and avoids DTO/VO conversion, making it possible to realize complex query in one line of code !","archived":false,"fork":false,"pushed_at":"2025-04-11T14:31:33.000Z","size":6964,"stargazers_count":1328,"open_issues_count":18,"forks_count":149,"subscribers_count":23,"default_branch":"dev","last_synced_at":"2025-04-11T15:47:16.546Z","etag":null,"topics":["devtool","java","orm","spring-boot"],"latest_commit_sha":null,"homepage":"https://bs.zhxu.cn","language":"JavaScript","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/troyzhxu.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-06-13T13:19:46.000Z","updated_at":"2025-04-11T14:31:37.000Z","dependencies_parsed_at":"2023-12-13T04:23:35.676Z","dependency_job_id":"6382a83b-cc07-400d-805b-e621997a13e5","html_url":"https://github.com/troyzhxu/bean-searcher","commit_stats":null,"previous_names":[],"tags_count":74,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troyzhxu%2Fbean-searcher","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troyzhxu%2Fbean-searcher/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troyzhxu%2Fbean-searcher/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troyzhxu%2Fbean-searcher/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/troyzhxu","download_url":"https://codeload.github.com/troyzhxu/bean-searcher/tar.gz/refs/heads/dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248437550,"owners_count":21103404,"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":["devtool","java","orm","spring-boot"],"created_at":"2024-09-24T20:36:02.283Z","updated_at":"2026-05-13T04:01:12.544Z","avatar_url":"https://github.com/troyzhxu.png","language":"JavaScript","funding_links":[],"categories":["数据库开发","JavaScript"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://bs.zhxu.cn/\" target=\"_blank\"\u003e\n    \u003cimg width=\"128\" src=\"./assets/logo.png\" alt=\"logo\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://maven-badges.herokuapp.com/maven-central/com.ejlchina/bean-searcher/\"\u003e\u003cimg src=\"https://maven-badges.herokuapp.com/maven-central/com.ejlchina/bean-searcher/badge.svg\" alt=\"Maven Central\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://gitee.com/troyzhxu/bean-searcher/blob/master/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/hexpm/l/plug.svg\" alt=\"License\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/troyzhxu\"\u003e\u003cimg src=\"https://img.shields.io/badge/%E4%BD%9C%E8%80%85-troyzhxu-orange.svg\" alt=\"Troy.Zhou\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nEnglish | [中文](./README.zh-CN.md)\n\n* Documentation：https://bs.zhxu.cn\n* **阿里云最低 1 折**：https://www.aliyun.com/minisite/goods?userCode=zugtbi5w\n* JueJin blogs：\n  - [Writing code like this is 100 times more efficient than using MyBatis directly!](https://juejin.cn/post/7027733039299952676)\n  - [What's the difference between Bean Searcher and MyBatis Plus?](https://juejin.cn/post/7092411551507808264)\n  \n* Only one line of code to achieve:\n  - Retrieval from multi tables\n  - Pagination by any field\n  - Combined filter by any field \n  - Sorting by any field \n  - Summaries with multi field\n  - Return VO directly\n\n* Design thinking: [Bean Searcher's thinking](https://bs.zhxu.cn/guide/latest/introduction.html#%E8%AE%BE%E8%AE%A1%E5%93%B2%E5%AD%A6)\n\n* Architecture:\n\n![](./assets/architecture.jpg)\n\n* Change log：[CHANGELOG](./CHANGELOG.md)\n* Performance：[see the report](./performance/README.md)\n* Gitee 企业版：https://gitee.com/enterprises?invite_code=Z2l0ZWUtMTM5MzQxMg%3D%3D\n\n### ✨ Features\n\n* Support **one entity mapping to multi tables**\n* Support **dynamic field operator**\n* Support **group and aggregation query**\n* Support **Select | Where | From subquery**\n* Support **embedded params in entity**\n* Support **field converters**\n* Support **sql interceptors**\n* Support **sql dialect extension**\n* Support **multi datasource and dynamic datasource**\n* Support **annotation omitting and customizing**\n* Support **field operator extension**\n* and so on\n\n### ⁉️WHY\n\n#### This is not a repeating wheel\n\nAlthough CREATE/UPDATE/DELETE are the strengths of Hibernate, MyBatis, DataJDBC and other ORM, queries, especially complex list queries with **multi conditions**, **multi tables**, **paging**, **sorting**, have always been their weaknesses.\n\nTraditional ORM is difficult to realize a complex list retrieval with less code, but **Bean Searcher** has made great efforts in this regard. These complex queries can be solved in almost one line of code.\n\n* For example, such a typical requirement：\n\n![](./assets/case.png)\n\nThe back-end needs to write a retrieval API, and if it is written with traditional ORM, the complexity of the code is very high\n\nBut Bean Searcher can：\n\n### 💥 Achieved with one line of code\n\nFirst, you have an Entity class:\n\n```java\n@SearchBean(tables=\"user u, role r\", joinCond=\"u.role_id = r.id\", autoMapTo=\"u\")\npublic class User {\n  private long id;\n  private String username;\n  private int status;\n  private int age;\n  private String gender;\n  private Date joinDate;\n  private int roleId;\n  @DbField(\"r.name\")\n  private String roleName;\n  // Getters and setters...\n}\n```\n\nThen you can complete the API with one line of code :\n\n```java\n@RestController\n@RequestMapping(\"/user\")\npublic class UserController {\n\n    @Autowired\n    private BeanSearcher beanSearcher;              // Inject BeanSearcher\n\n    @GetMapping(\"/index\")\n    public SearchResult\u003cUser\u003e index(HttpServletRequest request) {\n        // Only one line of code written here\n        return beanSearcher.search(User.class, MapUtils.flat(request.getParameterMap()), new String[]{ \"age\" });\n    }\n\n}\n```\n\nThis line of code can achieve：\n\n* **Retrieval from multi tables**\n* **Pagination by any field**\n* **Combined filter by any field**\n* **Sorting by any field**\n* **Summary with `age` field**\n\nFor example, this API can be requested as follows:\n\n* `GET: /user/index`\n  \n  Retrieving by default pagination:\n  ```json\n  {\n    \"dataList\": [\n      {\n        \"id\": 1,\n        \"username\": \"Jack\",\n        \"status\": 1,\n        \"age\": 25,\n        \"gender\": \"Male\",\n        \"joinDate\": \"2021-10-01\",\n        \"roleId\": 1,\n        \"roleName\": \"User\"\n      },\n      ...     // 15 records default\n    ],\n    \"totalCount\": 100,\n    \"summaries\": [\n      2500    // age statistics\n    ]\n  }\n  ```\n  \n* `GET: /user/index? page=1 \u0026 size=10`\n  \n  Retrieval by specified pagination\n\n* `GET: /user/index? status=1`\n  \n  Retrieval with `status = 1` by default pagination\n\n* `GET: /user/index? name=Jac \u0026 name-op=sw`\n  \n  Retrieval with `name` starting with `Jac` by default pagination\n\n* `GET: /user/index? name=Jack \u0026 name-ic=true`\n  \n  Retrieval with `name = Jack`(case ignored) by default pagination\n\n* `GET: /user/index? sort=age \u0026 order=desc`\n   \n  Retrieval sorting by `age` descending and by default pagination\n\n* `GET: /user/index? onlySelect=username,age`\n\n  Retrieval `username,age` only by default pagination:\n  ```json\n  {\n    \"dataList\": [\n      {\n        \"username\": \"Jack\",\n        \"age\": 25,\n      },\n      ...     // 15 records default\n    ],\n    \"totalCount\": 100,\n    \"summaries\": [\n      2500    // age statistics\n    ]\n  }\n  ```\n* `GET: /user/index? selectExclude=joinDate`\n\n  Retrieving `joinDate` excluded default pagination\n\n### ✨ Parameter builder\n\n```java\nMap\u003cString, Object\u003e params = MapUtils.builder()\n        .selectExclude(User::getJoinDate)                 // Exclude joinDate field\n        .field(User::getStatus, 1)                        // Filter：status = 1\n        .field(User::getName, \"Jack\").ic()                // Filter：name = 'Jack' (case ignored)\n        .field(User::getAge, 20, 30).op(Opetator.Between) // Filter：age between 20 and 30\n        .orderBy(User::getAge, \"asc\")                     // Sorting by age ascending \n        .page(0, 15)                                      // Pagination: page=0 and size=15\n        .build();\nList\u003cUser\u003e users = beanSearcher.searchList(User.class, params);\n```\n\n**Demos**：\n\n* [v4.x - demos](./bean-searcher-demos)\n* [v3.x - demos](https://gitee.com/troyzhxu/bean-searcher/tree/v3.8/bean-searcher-demos)\n\n### 🚀 Rapid development\n\nUsing Bean Searcher can greatly save the development time of the complex list retrieval apis!\n\n* An ordinary complex list query requires only one line of code\n* Retrieval from single table can reuse the original `domain`, without defining new `Entity`\n\n### 🌱 Easy integration\n\nBean Searcher can work with any JavaWeb frameworks, such as: SpringBoot, SpringMVC, Grails, Jfinal and so on.\n\n#### SpringBoot / Grails\n\nAll you need is to add a dependence:\n\n```groovy\nimplementation \"cn.zhxu:bean-searcher-boot-stater:${latestVersion}\"\n```\n\nand then you can inject Searcher into a `Controller` or `Service`:\n\n```groovy\n/**\n * Inject a MapSearcher, which retrieved data is Map objects\n */\n@Autowired\nprivate MapSearcher mapSearcher;\n\n/**\n * Inject a BeanSearcher, which retrieved data is generic objects\n */\n@Autowired\nprivate BeanSearcher beanSearcher;\n```\n\n#### Solon Project\n\nAll you need is to add a dependence:\n\n```groovy\nimplementation \"cn.zhxu:bean-searcher-solon-plugin:${latestVersion}\"\n```\n\nand then you can inject Searcher into a `Controller` or `Service`:\n\n```groovy\n/**\n * Inject a MapSearcher, which retrieved data is Map objects\n */\n@Inject\nprivate MapSearcher mapSearcher;\n\n/**\n * Inject a BeanSearcher, which retrieved data is generic objects\n */\n@Inject\nprivate BeanSearcher beanSearcher;\n```\n\n#### Other frameworks\n\nAdding this dependence:\n\n```groovy\nimplementation \"cn.zhxu:bean-searcher:${latestVersion}\"\n```\n\nthen you can build a `Searcher` with `SearcherBuilder`:\n\n```java\nDataSource dataSource = ...     // Get the dataSource of the application\n\n// DefaultSqlExecutor suports multi datasources\nSqlExecutor sqlExecutor = new DefaultSqlExecutor(dataSource);\n\n// build a MapSearcher\nMapSearcher mapSearcher = SearcherBuilder.mapSearcher()\n        .sqlExecutor(sqlExecutor)\n        .build();\n\n// build a BeanSearcher\nBeanSearcher beanSearcher = SearcherBuilder.beanSearcher()\n        .sqlExecutor(sqlExecutor)\n        .build();\n```\n\n### 🔨 Easy extended\n\nYou can customize and extend any component in Bean Searcher .\n\nFor example:\n* Customizing [`FieldOp`](/bean-searcher/src/main/java/cn/zhxu/bs/FieldOp.java) to support other field operator\n* Customizing [`DbMapping`](/bean-searcher/src/main/java/cn/zhxu/bs/DbMapping.java) to support other ORM‘s annotations\n* Customizing [`ParamResolver`](/bean-searcher/src/main/java/cn/zhxu/bs/ParamResolver.java) to support JSON query params\n* Customizing [`FieldConvertor`](/bean-searcher/src/main/java/cn/zhxu/bs/FieldConvertor.java) to support any type of field\n* Customizing [`Dialect`](/bean-searcher/src/main/java/cn/zhxu/bs/dialect/Dialect.java) to support more database\n* and so and\n\n### 📚 Detailed documentation\n\nReference ：https://bs.zhxu.cn\n\n### 🤝 Friendship links\n\n[**[ Sa-Token ]** 一个轻量级 Java 权限认证框架，让鉴权变得简单、优雅！](https://github.com/dromara/Sa-Token)\n\n[**[ Fluent MyBatis ]** MyBatis 语法增强框架, 综合了 MyBatisPlus, DynamicSql,Jpa 等框架的特性和优点，利用注解处理器生成代码](https://gitee.com/fluent-mybatis/fluent-mybatis)\n\n[**[ OkHttps ]** 轻量却强大的 HTTP 客户端，前后端通用，支持 WebSocket 与 Stomp 协议](https://gitee.com/troyzhxu/okhttps)\n\n[**[ hrun4j ]** 接口自动化测试解决方案 --工具选得好，下班回家早；测试用得对，半夜安心睡 ](https://github.com/lematechvip/hrun4j)\n\n[**[ JsonKit ]** 超轻量级 JSON 门面工具，用法简单，不依赖具体实现，让业务代码与 Jackson、Gson、Fastjson 等解耦！](https://gitee.com/troyzhxu/xjsonkit)\n\n[**[ Free UI ]** 基于 Vue3 + TypeScript，一个非常轻量炫酷的 UI 组件库 ！](https://gitee.com/phoeon/free-ui)\n\n\n### ❤️ How to contribute\n\n1. Fork code!\n2. Create your own branch: `git checkout -b feat/xxxx`\n3. Submit your changes: `git commit -am 'feat(function): add xxxxx'`\n4. Push your branch: `git push origin feat/xxxx`\n5. submit `pull request`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftroyzhxu%2Fbean-searcher","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftroyzhxu%2Fbean-searcher","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftroyzhxu%2Fbean-searcher/lists"}