# 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 id4.3 between@Query(":id")
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数据库,效率的话,暂时没测试,但是似乎没那么高...