{"id":38055945,"url":"https://github.com/sondertara/joya","last_synced_at":"2026-01-16T20:24:40.519Z","repository":{"id":45865736,"uuid":"433305245","full_name":"sondertara/joya","owner":"sondertara","description":"JPA extensions and elegant dynamic query","archived":false,"fork":false,"pushed_at":"2023-01-18T12:25:05.000Z","size":1159,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2023-07-02T00:06:36.701Z","etag":null,"topics":["jdbc","jpa-extension","jpa-hibernate","jpa-plus","sql-extension"],"latest_commit_sha":null,"homepage":"https://blog.sondertara.com/joya/","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/sondertara.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-11-30T05:26:29.000Z","updated_at":"2022-10-27T08:27:13.000Z","dependencies_parsed_at":"2023-02-10T15:00:45.527Z","dependency_job_id":null,"html_url":"https://github.com/sondertara/joya","commit_stats":null,"previous_names":[],"tags_count":7,"template":null,"template_full_name":null,"purl":"pkg:github/sondertara/joya","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sondertara%2Fjoya","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sondertara%2Fjoya/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sondertara%2Fjoya/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sondertara%2Fjoya/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sondertara","download_url":"https://codeload.github.com/sondertara/joya/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sondertara%2Fjoya/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28482267,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["jdbc","jpa-extension","jpa-hibernate","jpa-plus","sql-extension"],"created_at":"2026-01-16T20:24:40.373Z","updated_at":"2026-01-16T20:24:40.488Z","avatar_url":"https://github.com/sondertara.png","language":"Java","funding_links":[],"categories":["Java"],"sub_categories":[],"readme":"# 🥬 Joya\n\n![GitHub Workflow Status](https://img.shields.io/github/workflow/status/sondertara/joya/Java%20CI%20with%20Gradle) ![Maven Central](https://img.shields.io/maven-central/v/com.sondertara/joya) ![GitHub](https://img.shields.io/github/license/sondertara/joya)\n\n\u003e Joya 是对`Spring Data JPA` 扩展，JPA本身功能已经很强大了，但是复杂查询语句`HQL`\n\u003e 通常都是大量字符串拼接，不利于维护和阅读，提供优雅、易读和强大的链式查询语句的`Joya`应运而生\n\n## 🍹 项目特性\n\n- 基于`Hibernate NativeQuery` 进行扩展,支持全字段查询和指定字段查询,支持多种风格灵活易用\n- 兼容JPA，可插拔式集成，无需修改任何代码，不影响`JPA和Hibernate` 原有功能和特性\n- 作为 JPA 的扩展和增强，兼容 Spring Data JPA 原有功能和各种特性\n- 拥有使用原生SQL语句的极致体验\n- SQL结果可返回指定对象实体,同样支持单个字段返回包装类和`String`类\n- 可扩展性强,兼容其他ORM框架底层工作量小\n\n## 🎯 使用前提\n\n适用于 使用Java `Spring Data JPA` 和`JDK 1.8` 及以上的项目,完美兼容`Spring Boot 2.x`\n\n## 🧩 项目集成\n\n### 1.引入依赖\n\nMaven Project\n\n```xml\n\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.sondertara\u003c/groupId\u003e\n    \u003cartifactId\u003ejoya\u003c/artifactId\u003e\n    \u003cversion\u003e0.2.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nGradle Project\n\n```groovy\nimplementation 'com.sondertara:joya:0.2.0'\n```\n\n### 2.添加配置\n\n以`Spring boot` 项目为例,注入Bean.\n\n```java\n@Bean\npublic JoyaRepositoryFactoryBean joyaRepositoryFactoryBean(){\n        return new JoyaRepositoryFactoryBean();\n        }\n```\n\n通过 JoyaRepositoryFactoryBean 会注入 `JoyaRepository` 和`JoyaSpringContext`(一个Spring全局类)\n\n### 3.application.yml 配置（可选的）\n\n```yaml\njoya:\n  # 是否打印sql日志\n  sql-view: true\n```\n\n## 🍱 使用示例\n\nJoya 主要提供NativeSqlQuery 来处理查询语句,关于使用有如下特殊说明：\n\n\n\u003e select,from和where语句中都可以使用原生sql字符串方式来拼接查询\n\u003e\n\u003e Joya默认会为表生成别名，按照表在select和where部分第一次出现的顺序(select)，别名依次为 t0,t1... 如果要添加自定义的sql，请使用表别名\n\u003e\n\u003e 对于联表查询到实体，避免字段冲突。如果有相同的column字段,默认会使用第一个表中的值映射到目标实体,也可以为字段指定别名来都映射到目标实体\n\u003e\n\u003e 针对where语句中的subQuery,如果where是AND查询则subQuery联接条件为OR,反之where联接为OR,subQuery则为AND\n\n```text\n  // SQL编写风格\n  \n  NativeSqlQuery query = NativeSqlQuery.builder()\n           .select()\n           .from()\n           .where()\n           .groupBy()\n           .having()\n           .orderBy()\n           .build();\n```\n\nJoyaRepository中方法摘要\n\n```java\n/**\n * 查询list \n * @param sql 原生sql\n * @param clazz 目标实体\n * @param params 参数\n * @param \u003cT\u003e 泛型\n * @return list\n */\n@SuppressWarnings(\"unchecked\")\npublic\u003cT\u003e List\u003cT\u003e findListBySql(String sql,Class\u003cT\u003e clazz,Object...params);\n\n/**\n *  find to list \n * @param nativeSql native query\n * @param resultClass result class\n * @param \u003cT\u003e generic\n * @return list\n */\n@SuppressWarnings(\"unchecked\")\npublic\u003cT\u003e List\u003cT\u003e findListBySql(NativeSqlQuery nativeSql,Class\u003cT\u003e resultClass);\n\n\n/**\n * 分页查询\n *\n * @param resultClass 查询结果接收class\n * @param queryParam  查询数据\n * @param targetClass 查询数据库表\n * @param \u003cT\u003e         泛型\n * @return 分页数据\n */\npublic\u003cT\u003e PageResult\u003cT\u003e queryPage(PageQueryParam queryParam,Class\u003cT\u003e resultClass,Class\u003c?\u003e...targetClass)\n\n\n/**\n * 分页查询\n *\n * @param resultClass 查询结果接收class\n * @param queryParam  查询数据\n * @param \u003cT\u003e         泛型\n * @param joinPart    join语句\n * @return 分页数据\n */\npublic\u003cT\u003e PageResult\u003cT\u003e queryPage(PageQueryParam queryParam,Class\u003cT\u003e resultClass,UnaryOperator\u003cJoinCriterion\u003e joinPart)\n\n\n/**\n * 通过sql 分页查询\n *\n * @param nativeSql   查询语句\n * @param resultClass 结果映射class\n * @param pageNo      page\n * @param pageSize    pageSize\n * @param \u003cT\u003e         result\n * @return result\n */\n@SuppressWarnings(\"unchecked\")\npublic\u003cT\u003e PageResult\u003cT\u003e queryPage(NativeSqlQuery nativeSql,Class\u003cT\u003e resultClass,Integer pageNo,Integer pageSize)\n\n```\n\n### 1.单表查询\n\n- 查询全部字段\n\n```java\n\npublic class Test {\n    /**\n     * 等同于select * from xxx , 默认表中的字段全部列出\n     */\n    @Test\n    public void testSelectAll() {\n        // SELECT t0.id,t0.user_name,t0.user_email,t0.user_phone,t0.age FROM user AS t0 WHERE t0.user_name = ?1\n\n        //使用function函数和 entity对于的class类\n        NativeSqlQuery query = NativeSqlQuery.builder()\n                .select()\n                .from(UserPo.class)\n                .where(w -\u003e w.eq(UserPo::getUserName, \"张三\"))\n                .build();\n\n        //使用字符串格式\n        NativeSqlQuery query = NativeSqlQuery.builder()\n                .select()\n                .from(\"user AS t0\")\n                .where(w -\u003e w\n                        //.eq(\"t0.user_name\",\"张三\")) 下划线格式\n                        .eq(\"t0.userName\", \"张三\")) //驼峰格式\n                .build();\n\n        // 映射到UserDTO\n        List\u003cUserDTO\u003e list = joyaRepository.findListBySql(query, UserDTO.class);\n    }\n}\n```\n\n- 指定字段\n\n```java\n\npublic class Test {\n    @Test\n    public void testSelectSome() {\n\n        // SELECT t0.id, t0.user_name FROM user AS t0 WHERE t0.user_name = ?1\n\n        // 使用function函数接口 支持选择1-12个字段\n        NativeSqlQuery query = NativeSqlQuery.builder()\n                .select(UserPo::getId, UserPo::getUserName)\n                .from(UserPo.class)\n                .where(w -\u003e w.eq(UserPo::getUserName, \"张三\"))\n                .build();\n\n        //使用UnaryOperator 函数接口\n        NativeSqlQuery query1 = NativeSqlQuery.builder()\n                .select((UnaryOperator\u003cSelectCriterion\u003e) s -\u003e {\n                    s.add(UserPo::getUserName).add(UserPo::getId);\n                    return s;\n                })\n                .from(UserPo.class)\n                .where(w -\u003e w.eq(UserPo::getUserName, \"张三\"))\n                .build();\n\n        //字符串格式指定字段\n        NativeSqlQuery query3 = NativeSqlQuery.builder()\n                .select(\"t0.id\", \"t0.userName\")\n                //.select(\"t0.id\",\"t0.user_name\")\n                .from(UserPo.class)\n                .where(w -\u003e w.eq(UserPo::getUserName, \"张三\"))\n                .build();\n\n        List\u003cUserDTO\u003e list = joyaRepository.findListBySql(query, UserDTO.class);\n\n        // 查询单个字段映射到包装类或String\n        //SELECT t0.user_name FROM user AS t0 WHERE t0.user_name = ?1\n        NativeSqlQuery query3 = NativeSqlQuery.builder()\n                .select(UserPo::getUserName)\n                .from(UserPo.class)\n                .where(w -\u003e w.eq(UserPo::getUserName, \"张三\"))\n                .build();\n\n        List\u003cString\u003e list1 = joyaRepository.findListBySql(query3, String.class);\n    }\n}\n```\n\n### 2.联表查询\n\n```java\n\npublic class Test {\n    @Test\n    public void testJoin() {\n        // 联接字段在where 语句中\n        //SELECT t0.id,t0.user_name,t0.user_email,t0.user_phone,t0.age,t1.user_id,t1.account_expired_time,t1.password_expired_time,t1.ext_data FROM user AS t0, user_extend AS t1 WHERE t0.id = t1.user_id AND t0.user_name = ?1\n        NativeSqlQuery query = NativeSqlQuery.builder()\n                .select()\n                .from(UserPo.class, UserExtendPo.class)\n                .where(w -\u003e w\n                        .eq(UserPo::getId, UserExtendPo::getUserId)\n                        .eq(UserPo::getUserName, \"张三\"))\n                .build();\n\n        // 联接字段在from语句中 支持inner join,left join和 right join三种方式,目前为了提升效率,限制最大支持三张表联表查询\n\n        //SELECT t0.id,t0.user_name,t0.user_email,t0.user_phone,t0.age,t1.user_id,t1.account_expired_time,t1.password_expired_time,t1.ext_data FROM user AS t0 JOIN user_extend AS t1 ON t0.id = t1.user_id WHERE t0.user_name = ?1\n        NativeSqlQuery query1 = NativeSqlQuery.builder()\n                .select()\n                .from(j -\u003e j.join(UserPo::getId, UserExtendPo::getUserId))\n                .where(w -\u003e w\n                        .eq(UserPo::getUserName, \"张三\"))\n                .build();\n\n\n        //对于冲突字段可以指定别名,如user表和user_extend表同时有 updateTime字段,可以通过指定别名来避免字段值覆盖\n        // SELECT t0.id,t0.user_name,t0.user_email,t0.user_phone,t0.update_time,t1.update_time AS modifyTime,t1.account_expired_time,t1.password_expired_time,t1.ext_data FROM user AS t0 JOIN user_extend AS t1 ON t0.id = t1.user_id WHERE t0.user_name = ?1\n        NativeSqlQuery query3 = NativeSqlQuery.builder()\n                .select()//查询全部字段\n                .specificS(\"t1.updateTime AS modifyTime\") //将user_extend中重名的updateTime 指定为modifyTime\n                .from(j -\u003e j.join(UserPo::getId, UserExtendPo::getUserId))\n                .where(w -\u003e w\n                        .eq(UserPo::getUserName, \"张三\"))\n                .build();\n    }\n}\n```\n\n### 3.分页查询\n\n在Joya中为分页查询封装了`PageQueryParam` 提供给restFul接口使用\n\n```java\n/**\n * 分页查询参数支持常用封装\n */\npublic class PageQueryParam extends JoyaQuery implements Serializable {\n    /**\n     * 分页大小\n     */\n    private Integer pageSize = 10;\n    /**\n     * 页数 默认从0开始\n     */\n    private Integer page = 0;\n    /**\n     * 连接类型 默认and\n     */\n    private LinkType linkType = LinkType.AND;\n    /**\n     * 排序字段\n     */\n    private List\u003cOrderParam\u003e orderList = Lists.newArrayList();\n\n    /**\n     * 搜索参数\n     */\n    private List\u003cSearchParam\u003e params = Lists.newArrayList();\n\n    public enum LinkType {\n        /**\n         *\n         */\n        AND,\n        OR;\n\n    }\n}\n```\n\n如有如下查询场景\n\u003e 分页关联查询user表和user_extend表,查询条件为userName like '张三%'并且 age\u003e18,按照user表中的id降序\n\n那么接口请求的`PageQueryParam`则为\n\n```json\n{\n  \"orderList\": [\n    {\n      \"fieldName\": \"t0.id\",\n      \"orderType\": \"DESC\"\n    }\n  ],\n  \"page\": 0,\n  \"pageSize\": 10,\n  \"params\": [\n    {\n      \"fieldName\": \"t0.userName\",\n      \"fieldValue\": \"张三\",\n      \"operator\": \"LIKE_R\"\n    },\n    {\n      \"fieldName\": \"t0.age\",\n      \"fieldValue\": 18,\n      \"operator\": \"GT\"\n    }\n  ]\n}\n```\n\n使用Joya查询方法有如下两种：\n\n- 分页查询(指定join字段)\n\n```java\nPageQueryParam pageQueryParam=JSON.parseObject(jsonString,PageQueryParam.class);\n\n        PageResult\u003cUserDTO\u003e pageResult=joyaRepository.queryPage(pageQueryParam,UserDTO.class,j-\u003ej.join(UserPo::getId,UserExtendPo::getUserId));\n```\n\n- 分页查询(指定where语句中的联接字段)\n\n```java\n PageQueryParam pageQueryParam1=JSON.parseObject(\"\",PageQueryParam.class);\n//附加where\n        pageQueryParam1.setSpecificW(\"t0.id=t1.userId\");\n\n//指定要查询的表，顺序要注意,因为别名按照先后顺序来生成\n        PageResult\u003cUserDTO\u003e pageResult=joyaRepository.queryPage(pageQueryParam,UserDTO.class,UserPo.class,UserExtendPo.class);\n```\n\n### 4.特殊定制化查询\n\n在Joya中,where 查询语句支持常用查询,也可以通过`specificW`方法来添加特殊查询语句\n\n```java \n.where(w -\u003e w\n            .eq() // =\n            .gt() // \u003e\n            .lt() // \u003c\n            .gte() // \u003e=\n            .lte() // \u003c=\n            .isNull() // is null\n            .isNotNull() // is not null\n            .in() // in \n            .notIn() // not in\n            .endsWith() // like '%a'\n            .contains() // like '%a%'\n            .startsWith() // like 'a%'\n            .specificS()) //指定特殊的查询语句\n```\n\nwhere 查询语句默认是`AND`条件联接,可以选择`OR`条件联接\n\n```java\n   //SELECT t0.id,t0.user_name,t0.user_email,t0.user_phone,t0.age,t1.user_id,t1.salt,t1.account_expired_time,t1.password_expired_time,t1.ext_data FROM user AS t0, user_extend AS t1 WHERE t0.user_name = ?1 OR t0.user_name = ?2 OR ( t0.age \u003e= ?2 AND t0.user_phone LIKE ?2 )\n        NativeSqlQuery query=NativeSqlQuery.builder()\n                .select()\n                .from(UserPo.class,UserExtendPo.class)\n        .where(w-\u003ew\n        .eq(UserPo::getUserName,\"张三\")\n        .eq(UserPo::getUserName,\"李四\")\n\n        .subQuery(q-\u003eq.gte(UserPo::getAge,18).startsWith(UserPo::getUserPhone,\"1385\")),true)\n        .build();\n```\n\n## 🔌 参与贡献\n\nfork本项目,添加features或bugfix,提交Pull Requests\n\n## 📗 开源许可证\n\nJoya 遵守 [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0) 许可证。\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsondertara%2Fjoya","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsondertara%2Fjoya","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsondertara%2Fjoya/lists"}