# expression-template **Repository Path**: li-dongfang/expression-template ## Basic Information - **Project Name**: expression-template - **Description**: expressionjdtemplate,想要简化sql书写 - **Primary Language**: Java - **License**: GPL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-12-31 - **Last Updated**: 2023-12-31 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README #### ### ** ExpressionSql简介** A jdbcTemplate sql tool; 为什么写这个东西,就是觉得mybatis的实现很有意思,但是又不想把它封装成JPA,正好某日看见正则表达式,想了下,要不试试这个。于是就有了这个东西。 本质上也是不想写太多的XML,毕竟动态查询,一下来就是一串。但是实际上吧,开发中用的最多还是这东西。 所以突发奇想,要不自己造个轮子,虽然代码很烂...... Expression和Sql: 正常情况下,书写sql一般都会按照正规的sql标准书写,例如:select * from user where id=1,表和连表倒不是什么问题,问题是每次都要书写大量的列名,毕竟*这个东西在某些方面是不让使用的。 怎么样才能让这个工作更简单? 于是有了拆分的思路,将一个sql拆分成普通语句,列,查询条件和其他的排序等等。而需要处理的部分,恰恰是列和条件。 于是有了列标志引用和条件查询引用 select [@user] from user where 1=1 {@user::id:name:age:des}这种方式。 显然这对于简单的query来说又是复杂的,索性出现了expression Expression expression类似于一个表达式,通过解析这个表达式可以快速的生成相应的sql;表达式分为两种,第一种是实体类表达式,第二种是普通参数表达式。eg: ::user:id:name 以::开始,是一个实体类的表达式,后面的:是属性分割符号,代表当前实体类表达参数中的属性; :id这种就是一个param表达式,单纯的表示一个合法的方法参数id,当然也可以使用&进行混合使用 ### **规则** 1. 实体类表达式 @Query("::user:id:name") List queryUser(User user); 实体类表达式以::开始,后面的每个:依次表示user参数中的属性。 ::user:id:name 的含义即以user作为参数,查询user列表,其中使用的属性为user中的id,name,解析的时候会自动将该表达式解析为 select * from user where 1=1 and id=? and name=? 2. param表达式 @Query(":id") User queryUserById(Long id); :id 即表示method中的id参数,即以id作为查询条件,对应查询实体类user中的id,进行解 析,最终sql为:select * from user where 1=1 and id=1 同样的,如果是update和insert也会按照上面的规则进行解析处理 3.默认参数: 在某个param或者属性后面添加()即可以设定当前的默认参数 ::user:id(1) 即user中的属性id使用默认数值1 eg: @Query("::user:id(1)") User queryUserById(User user); 解析之后,sql为 select * from user where id=1; 4. 条件查询常用表达 4.1 large@Query("::user:>id") List queryUserIdLarger(User user);以>开始放到属性之前,即表示以该属性做larger处理,sql为:select * from user where 1=1 and id>?4.2 less:@Query("::user: queryUserIdLess(User user);同上,这是lessThean,sql:select * from user where idid") List queryUser(Long idStart, Long idEnd);between 以尖括号表示between中的数值,上述解析为:select * from user where id between ? and ?,只有当两个都不为空的时候,会设置between条件,分别对应sql中的两个参数4.4 like@Query(":%name") List queryUserByName(String name);%前置代表like,当前sql解析为:select * from user where 1=1 and name like %?% 5. 同样支持 |(or)!(not) |!(orNot)操作,具体实例如下:eg:@Query("::user:id:|name") List queryUserOr(User user);// or not like @Query("::user:id:|!%name") List queryUserOrNotLike(User user);@Query(":|!id") List queryUserOrNotBetween(Long id1, Long id2);@Query(":id:|!>id") List queryUserOrNotLarger(Long id);@Query(":id:|!表示,需要配合@in注解。eg:@Query(":id") List queryIn(@In Long[] ids); 会自动将ids解析成对应的sql ### ** 实体类列引用** 对于符合驼峰表达式的实体类和列可以直接使用实体类引用。方法如下: 在mapper中定义一个静态方法名称为ref,并在其上添加注解@EntityReferrence如下:@EntityReference( refs = { ``` @Ref(refId = "user", entity = User.class), @Ref(refId = "class", entity = User.U.class) ``` }) static void ref() {}此时会将在启动的时候解析引用,即refId和它对应的实体类,后续可以在列引用中使用。列引用:列引用以[]包裹,多个列引用以,分割,此时如果想要在select * from user where id=1中引用配置的实体类列可以改成如下写法:select [@user] from user where id=1;如果你只需要user中的几个属性那么可以如下进行操作:select [@user:id:name:age] from user where id=1当然如果是多表查询,可以在引用后添加括号指定当前entity列的引用别名,如下select[@user(u),@class(c)] from user u left join class c on c.main_id=u.id where u.id=1;如果需要指定列,可以在后面继续添加属性[@user:id:name:age] ### ** 动态SQL语句** 动态sql语句,相比起,这里的动态sql语句可以直接使用expression进行替换处理 @Query( ref = "userDto", value = "select [@user(u):id:name,@class(c):id:name] from user left join class c on c.main_id=u.id where 1=1 " + "{@u::user:id:name}" + "{@c::u:id:name}") List pageQueryUserJoin(User user, User.U u, Pager pager); 如上{}内的即是动态sql语句 动态sql语句 @u::user:id:name @表示动态sql语句的开始,u表示当前动态sql表达式对应的别名,id,name即查询使用的列,要求即是参数u中使用的字段名称与数据库中字段名称是驼峰对应的关系,这时候可以直接简化成如上写法 解析后即为 u.name=? and u.id=? 当然,这显然不足以书写负责的sql,此时就可以用上之前的like,between,and or等进行处理,如下 @Query( ref = "userDto", value = "select [@user(u):id:name,@class(c):id:name] from user left join class c on c.main_id=u.id where 1=1 " - "{@u::user:id:name}" - "{@c::u:id:%name:|%name}") List pageQueryUserJoin(User user, User.U u, Pager pager); ### 非对应列的处理 @Query( ref = "userDto", value = "select [@user(u):id:name,@class(c):id:name] from user left join class c on c.main_id=u.id where 1=1 " - "{@u::user:userId=id:userName=name}" - "{@c::u:id:name}") List pageQueryUserJoin(User user, User.U u, Pager pager); - 只需要通过=绑定数据库实际的列名称即可 ### 分页查询 分页查询只需要在参数中添加一个pager参数即可,默认返回一个pageData类。默认生成的sql会自动按照id升序排列,其他的分页需要自己单独写order条件 eg: @Query("::user:%name") PageData pageQuery(User user, Pager pager); pager: package org.example.jdbctemplate.page; public class Pager { private Integer pageNo; private Integer pageSize; ``` public Integer getPageNo() { return pageNo; } public void setPageNo(Integer pageNo) { this.pageNo = pageNo; } public Integer getPageSize() { return pageSize; } public void setPageSize(Integer pageSize) { this.pageSize = pageSize; } ``` } pageData: package org.example.jdbctemplate.page; import java.util.List; public class PageData { ``` private List data; private int total; private int pageNo; private int pageSize; public List getData() { return data; } public void setData(List data) { this.data = data; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } public int getPageNo() { return pageNo; } public void setPageNo(int pageNo) { this.pageNo = pageNo; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } ``` } ###   **源码部分** 源码包:org.jdbctenplate 文件夹 ### ** 查询实例** (更多实例参考controller文件夹下的相关test用例) ### **example** localhost:8080/query SQL:select * from user where 1=1 ``` [ { "name": "xxx", "id": "1" }, { "name": "xxx", "id": "2" } ] ``` eg2: @Query("::user:id:name") List queryUser(User user); sql:select id,name from user where 1=1 and id='1' and name='x' result:[] 数据库中没有查到这条数据 eg:3 @Query(":id") User queryUserById(Long id); sql: select id,name from user where id=1; {     "id": 1,     "name": "xxx",     "uList": null } eg:4 非同名参数映射 @Query(":userId=id") User queryUserByIdS(Long userId); 默认将userId映射到列id SQL:select id,name from use where id=? 数据测试结果: {     "id": 1,     "name": "xxx",     "uList": null } eg5: default value set @Query("::user:id(3)") User queryUserById(User user); select * from user where id=3; eg:6 like @Query(":%name") List queryUserByName(String name); Sql: seletc * from user where name like '%?%'; eg"7:" between @Query(":id") List queryUser(Long idStart, Long idEnd); select id,name from user where 1=1 and id between '1' and '4' eg8: > @Query("::user:>id") List queryUserIdLarger(User user); select id,name from user where 1=1 and id>'1' eg9: < @Query("::user: queryUserIdLess(User user); select id,name from user where 1=1 and id<'2' eg10: composite @Query("::user:%name:>id&:id") List queryUser(User user, Long id); select id,name from user where 1=1 and name like '%x%' and id>'1' and id ='1' eg11: 动态sql查询 @Query( ref = "userDto", value = "select [@user(u),@class(c)] from user u left join class c on c.main_id=u.id where 1=1 " + "{@u::user:id:%name}" + "{@c::u:id:%name}") List queryUserJoin(User user, User.U u); select u.id,u.name,c.name,c.id from user u left join class c on c.main_id=u.id where 1=1 and u.id='1' and u.name like '%x%' and c.id='1' and c.name like '%x%' eg12 自动生成的pageQuery: pageQuery @Query("::user:%name") PageData pageQuery(User user, Pager pager); select id,name from user where 1=1 and name like '%x%' order by id asc  示例结果:   "data": [         {             "name": "3xxxx",             "id": "3"         },         {             "name": "4xxx",             "id": "4" ],     "total": 9,     "pageNo": 2,     "pageSize": 2 } eg13: @Query( ref = "userDto", value = "select [@user(u):id:name,@class(c):id:name] from user u left join class c on c.main_id=u.id where 1=1 " + "{@u::user:%name}" + "{@c::u:%name}" + "order by u.id asc") List pageQueryUserJoin(User user, User.U u, Pager pager); select u.id,u.name,c.name,c.id from user u left join class c on c.main_id=u.id where 1=1 and u.name like '%x%' and c.name like '%x%' order by u.id asc eg:14 使用vo进行数据库查询 @Query( ref = "userDto", value = "select [@user(u),@class(c)] from user u left join class c on c.main_id=u.id where 1=1 " + "{@u::userVo:%name}" + "{@c::userVo.u:%name}" + "order by id asc") List queryUserJoin(UserVo userVo); SQL:select u.id,u.name,c.name,c.id from user u left join class c on c.main_id=u.id where 1=1 and u.name like '%xx%' and c.name like '%xx%' order by u.id asc eg15: not larger使用 @Query(":!>id") List queryNotLarger(Long id); select id,name from user where 1=1 and id <'8' eg16:not less @Query(":! queryNotLess(Long id); select id,name from user where 1=1 and id >'1' eg17: not between @Query(":!id") List queryNotBetween(Long id1, Long id2); select id,name from user where 1=1 and id not between '1' and '4' eg18: 原生sql解析测试 @Query("select [@user] from user where id=:id") List queryOriginSql(Long id); select id,name from user where id='1' eg:19 原生sql 纯原生sql like需要特殊处理的地方需要自己特殊处理 @Query("select * from user where id=::user:id and name like '%:name%'") List queryOrigin(User user, String name); select * from user where id=1 and name like '%x%' eg:20 or not like 测试 @Query("::user:id:|!%name") List queryUserOrNotLike(User user); select id,name from user where 1=1 and id='1' or name not like '%x%' eg21: or not larger eg22: or not between @Query(":|!id") List queryUserOrNotBetween(Long id1, Long id2); select id,name from user where 1=1 or id not between '1' and '3' ### **说明** 因为时间的问题,只是适配了mysql数据库,效率的话,暂时没测试,但是似乎没那么高...