# sql-starts-rapid
**Repository Path**: natsuki_kining/sql-starts-rapid
## Basic Information
- **Project Name**: sql-starts-rapid
- **Description**: 快速动态查询
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 3
- **Forks**: 0
- **Created**: 2020-04-12
- **Last Updated**: 2024-06-22
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# sql-starts-rapid
-----
# 目录
* [介绍](#介绍)
* [简称ssr](#简称ssr)
* [主要功能](#主要功能)
* [使用场景](#使用场景)
* [目录结构](#目录结构)
* [各版本主功能说明](#各版本主功能说明)
* [使用说明](#使用说明)
* [快速体验](#快速体验)
* [简单sql查询](#简单sql查询)
* [带查询条件查询](#带查询条件查询)
* [返回封装的类型](#返回封装的类型)
* [快速入门](#快速入门)
* [新增表SSR_DYNAMIC_SQL](#新增表SSR_DYNAMIC_SQL)
* [引入依赖](#引入依赖)
* [添加包扫描路径](#添加包扫描路径)
* [在controller里注入Query并调用里面的方法](#在controller里注入Query并调用里面的方法)
* [进阶](#进阶)
* [Query接口介绍](#Query接口介绍)
* [返回指定的类型](#返回指定的类型)
* [分页跟排序](#分页跟排序)
* [Java拦截器使用](#Java拦截器使用)
* [脚本拦截器](#脚本拦截器)
* [自定义拦截器](#自定义拦截器)
* [数据处理脚本](#数据处理脚本)
* [多数据源](#多数据源)
* [sql生成](#sql生成)
* [根据表名生成](#根据表名生成)
* [根据实体名生成](#根据实体名生成)
* [sql生成自定义查询条件](#sql生成自定义查询条件)
* [根据查询参数默认规则生成查询条件](#根据查询参数默认规则生成查询条件)
* [自定义条件查询简单示例右模糊](#自定义条件查询简单示例右模糊)
* [多条件](#多条件)
* [缓存](#缓存)
* [内置缓存](#内置缓存)
* [自定义缓存](#自定义缓存)
* [orm框架](#orm框架)
* [MyBatis](#MyBatis)
* [hibernate](#hibernate)
* [自定义orm框架](#自定义orm框架)
* [自定义SSRDynamicSQL表名](#自定义SSRDynamicSQL表名)
* [bean说明文档](#bean说明文档)
* [QueryParams](#QueryParams)
* [QueryCondition](#QueryCondition)
* [QueryInfo](#QueryInfo)
* [QueryResult](#QueryResult)
* [QueryRule](#QueryRule)
* [QuerySQL](#QuerySQL)
* [SSRDynamicSQL](#SSRDynamicSQL)
* [Query](#Query)
* [注解](#注解)
* [项目工程介绍](#项目工程介绍)
* [ssr-core](#ssr-core)
* [ssr-hibernate](#ssr-hibernate)
* [ssr-mybatis](#ssr-mybatis)
* [test-ssr-hibernate](#test-ssr-hibernate)
* [test-ssr-mybatis](#test-ssr-mybatis)
* [使用示例](#使用示例)
----
# 介绍
## 简称ssr
> 下个项目->[ur](https://gitee.com/natsuki_kining/ultra-rare)
## 主要功能
* 可根据传入的参数动态生成查询sql
* 自带拦截器可修改传入的参数跟带入固定的查询条件(例如登录用户的id)
* 内部集成三种脚本语言可以预处理查询结果
* 集成hibernate跟mybatis两种orm查询框架
* 实现多数据源动态配置
## 使用场景
* 报表查询
* 不需要编写java代码便可构建一个SQL查询
* 经常需要修改SQL语句的查询
* 可以在运行时修改sql,而不用重启项目。
* 可以快速的新增一个查询功能,而不用写任何代码。
* 不用再每个查询都暴露一个api方法
## 目录结构
|模块名|介绍|
|-----|---|
|ssr-core|核心,主要实现|
|ssr-hibernate|hibernate实现|
|ssr-hibernate-spring-boot-starter|封装springboot hibernate starter|
|ssr-mybatis|mybatis实现|
|ssr-mybatis-spring-boot-starter|封装springboot mybatis实现 starter|
|test-ssr-hibernate|测试模块|
|test-ssr-hibernate-spring-boot-starter|测试模块|
|test-ssr-mybatis|测试模块|
|test-ssr-mybatis-spring-boot-starter|测试模块|
## 各版本主功能说明
* 第1.0版:
* 通过freemarker实现动态sql。
* Java拦截器,用于处理查询前后的数据。
* 脚本拦截器,可调用JavaScript,Python,Groovy等脚本语言处理数据。
* 缓存,sql查询效率,提供sql优化建议等工具。
* 多code查询,用于处理内部有多查询的情况。
* 多数据源,可以设置动态多数据源。
* 封装springboot starter
# 使用说明
## 快速体验
> 下面的测试例子运行的是test-ssr-mybatis项目
* ssr_user中的数据
### 简单sql查询
* 在ssr_dynamic_sql 表中新增数据:
```sql
INSERT INTO `ssr_dynamic_sql` (`ID`, `QUERY_CODE`, `SQL_TEMPLATE`) VALUES ('1', 'query-user', 'select * from ssr_user');
```
* postman请求
### 带查询条件查询
* 使用freemarker为sql添加查询条件
```sql
INSERT INTO `ssr_dynamic_sql` (`ID`, `QUERY_CODE`, `SQL_TEMPLATE`) VALUES ('1', 'query-user', 'select * from ssr_user \r\nwhere 1=1\r\n<#if name??><#noparse>\r\nand NAME like CONCAT(\'%\',#{name},\'%\')\r\n#noparse>#if>\r\n<#if userName??><#noparse>\r\nand USER_NAME like CONCAT(\'%\',#{userName},\'%\')\r\n#noparse>#if>\r\n<#if code??><#noparse>\r\nand `CODE` = #{code}\r\n#noparse>#if>');
```
> 其中`<#if>`为添加判断,`<#noparse>`为freemarker`#{}`转义
* postman请求
> 输出的查询sql语句为 select * from ssr_user where 1=1 and NAME like CONCAT('%',?,'%')
* postman请求
> 输出的查询sql语句为 select * from ssr_user where 1=1 and NAME like CONCAT('%',?,'%') and USER_NAME like CONCAT('%',?,'%')
### 返回封装的类型
* 在query接口里传入需要转换的类型
```
@PostMapping("queryUser")
public Object queryUser(@RequestBody QueryParams queryParams) throws ClassNotFoundException {
Class> aClass = Class.forName("com.natsuki_kining.ssr.test.entity.SSRUser");
List> result = this.query.queryList(queryParams, aClass);
return result;
}
```
## 快速入门
### 新增表SSR_DYNAMIC_SQL
脚本在file文件夹里,根据使用的数据库选择对应的脚本
### 引入依赖
* 根据需求引入相应的依赖包
默认实现了mybatis跟hibernate,如果项目是使用其他的orm框架的,可以引入ssr-core
com.natsuki_kining.ssr
ssr-core
1.0.0
* 然后实现QueryORM接口,如果是使用mybatis的可以直接引入
com.natsuki_kining.ssr
ssr-mybatis
1.0.0
* 如果是使用hibernate的则引入
com.natsuki_kining.ssr
ssr-hibernate
1.0.0
### 添加包扫描路径
com.natsuki_kining
### 在controller里注入Query并调用里面的方法
```java
@RestController
@RequestMapping("query")
public class QueryController {
@Autowired
private Query query;
@PostMapping("page")
public Object page(@RequestBody QueryParams queryParams) {
return this.query.query(queryParams);
}
}
```
## 进阶
### Query接口介绍
### 返回指定的类型
Query接口里的每个方法都有个重载方法,可传输指定的类型,直接调用为Map类型。
### 分页跟排序
* 分页
设置pageNo跟pageSize两个参数即可。
输出的sql语句:
> select * from ssr_user LIMIT 0,2
* 排序
设置sort参数即可
输出的sql语句:
> select * from ssr_user ORDER BY NAME DESC
### Java拦截器使用
* 直接继承AbstractQueryJavaIntercept类,然后重写里面方法,交给spring管理。如果没有`@QueryCode`加入这个注解,则默认拦截所有的查询。`@QueryCode`注解支持正则表达式,只拦截匹配的queryCode
例:
```java
@Component
public class SSRQueryIntercept extends AbstractQueryJavaIntercept {
@Override
public boolean preHandle(QueryParams queryParams) {
return true;
}
@Override
public void queryBefore(QueryParams queryParams, QueryInfo queryInfo, SSRDynamicSQL ssrDynamicSQL, Map map) {
System.out.println("master intercept:"+queryParams.getQueryCode());
}
@Override
public Object queryAfter(QueryParams queryParams, QueryInfo queryInfo, SSRDynamicSQL ssrDynamicSQL, Map map, Object data) {
return data;
}
}
```
* 拦截方法介绍
* preHandle 返回true则继续执行,返回false则不执行该查询。
* queryBefore 查询前参数处理。可以添加新的查询参数或者修改前端传来的参数。例如添加当前登录用户的id
* queryAfter 查询结果处理,例如屏蔽敏感信息。
#### 脚本拦截器
* 可以将数据处理写到数据库里,不需要编写java代码,可动态修改。默认实现了三种脚本处理。
#### 自定义拦截器
* 继承AbstractQueryJavaIntercept
* 重写里面的三个方法
* 加上`@Component`注解交给spring管理
* 加上`@QueryCode`注解,根据queryCode拦截,支持正则匹配
### 数据处理脚本
#### JavaScript
#### Python
#### Groovy
#### 自定义脚本脚本
* 继承AbstractQueryScriptIntercept
* 重写executeScript
* 加上`@Component`注解交给spring管理
* 加上`@ConditionalOnProperty`注解,按配置条件注入
* 在配置文件上加上注解里的条件
### 多数据源
#### 多数据源配置
```yaml
ssr:
multi-data-source:
数据源名称1:
username: database username
password: database password
url: database url
driver-class-name: database driver
……
数据源名称2:
username: database username
password: database password
url: database url
driver-class-name: database driver
……
……
```
#### 系统运行时添加数据源
* 注入`DynamicDataSourceHandle`
* 调用addDatasource方法,传入SSRDruidProperties即可。
例如:
```java
@RestController
@RequestMapping("dynamicDataSource")
public class DynamicDataSourceController {
@Autowired
private DynamicDataSourceHandle dataSourceHandle;
@PostMapping("addDataSource")
public Object addDataSource(@RequestBody SSRDruidProperties druidProperties){
return dataSourceHandle.addDatasource(druidProperties);
}
}
```
发送的数据:
```json
{
"dataSourceName":"数据源名称",
"url":"数据库连接",
"username":"用户名",
"password":"密码",
"driverClassName":"驱动类"
}
```
#### 多数据源使用
* 数据库表
DATA_SOURCE_NAME列为空,则使用默认数据源。
* 自动生成
queryCode:[表名/类名]:[generateByTable/generateByEntity]:[数据源的名称]
### sql生成
不需要在表中插入查询的sql数据
#### 根据表名生成
* 在配置文件夹中加入ssr.enable.generate-by-table=true
* queryCode写法规则:表名:[generateByTable][:][数据源的名称] ([]可不填)
* 例如: ssr_user:
* 数据源不写则使用默认数据源
* selectFields:查询字段,多个用英文逗号分隔
#### 根据实体名生成
* 在配置文件夹中加入ssr.enable.generate-by-entity=true
* queryCode写法规则:类全路径:[generateByEntity][:][数据源的名称] ([]可不填)
* 例如: com.natsuki_kining.ssr.test.entity.SSRUser:
* 数据源不写则使用默认数据源
* 类似需要加上注解`@TableName`,如果不加则按驼峰规则转换成表名
* selectFields:查询字段,多个用英文逗号分隔
#### sql生成自定义查询条件
* logicalOperator:默认值"AND"
* relationalOperator:默认值“=”
##### 根据查询参数默认规则生成查询条件
* JSON:
```json
{
"queryCode":"ssr_user:",
"params":{
"code":"227",
"user_name":"李会问"
}
}
```
* SQL:
```sql
SELECT * FROM ssr_user T1 WHERE 1=1 AND T1.CODE = ? AND T1.USER_NAME = ?
```
* 参数
> Parameters : [227, 李会问]
> Types : [VARCHAR, VARCHAR]
* 结果
```json
[
{
"password": "651860cc8dd74513ae606a02e656a311",
"code": "227",
"user_name": "李会问",
"name": "11b3c4dbc8424171b09cc3d0f280f4bb",
"id": 227
}
]
```
##### 自定义条件查询简单示例右模糊
* JSON
```json
{
"queryCode":"ssr_user:",
"condition":[
{
"fieldName":"user_name",
"value":"李机",
"relationalOperator":"rl"
}
]
}
```
* SQL
```sql
SELECT * FROM ssr_user T1 WHERE 1=1 AND T1.USER_NAME LIKE concat(? ,'%')
```
* 参数
> Parameters : [李机]
> Types : [VARCHAR]
* 结果
```json
[
{
"password": "90c1b9a427e447da982a98641300d3d8",
"code": "3114",
"user_name": "李机夫",
"name": "4af4bfeb0f8c4b85826c22c147836927",
"id": 3114
},
{
"password": "4689d61c47ef48b2808bc187fb029c21",
"code": "3240",
"user_name": "李机写",
"name": "7351a02b824e4ce5849f4dd2da6ecba0",
"id": 13240
}
]
```
##### 多条件
* JSON
```json
{
"queryCode":"ssr_user:",
"condition":[
{
"fieldName":"user_name",
"value":"李",
"relationalOperator":"rl"
},
{
"fieldName":"user_name",
"value":"向",
"relationalOperator":"ll"
}
]
}
```
* SQL
```sql
SELECT * FROM ssr_user T1 WHERE 1=1 AND T1.USER_NAME LIKE concat(? ,'%') AND T1.USER_NAME LIKE concat('%',? )
```
* 参数
> Parameters : [李, 向]
> Types : [VARCHAR, VARCHAR]
* 结果
```json
[
{
"password": "b90d9dfbd9bb42baa19a8559eebcc7fb",
"code": "267",
"user_name": "李口向",
"name": "b06bdd2c8f5a4c8fb25e5797597992f3",
"id": 267
}
]
```
##### 分组查询
```json
{
"queryCode":"ssr_user:",
"condition":[
{
"condition":[
{
"fieldName":"user_name",
"value":"李",
"relationalOperator":"rl"
},{
"fieldName":"user_name",
"value":"问",
"relationalOperator":"ll"
}
]
},
{
"logicalOperator":"or",
"condition":[
{
"fieldName":"password",
"value":"aa",
"relationalOperator":"ll"
},{
"fieldName":"password",
"value":"ea",
"relationalOperator":"rl"
}
]
}
]
}
```
* SQL
```sql
SELECT * FROM ssr_user T1 WHERE 1=1 AND ( T1.USER_NAME LIKE concat(? ,'%') AND T1.USER_NAME LIKE concat('%',? ) ) OR ( T1.PASSWORD LIKE concat('%',? ) AND T1.PASSWORD LIKE concat(? ,'%') )
```
* 参数
> Parameters : [李, 问, aa, ea]
> Types : [VARCHAR, VARCHAR, VARCHAR, VARCHAR]
* 结果集
```json
[
{
"password": "651860cc8dd74513ae606a02e656a311",
"code": "227",
"user_name": "李会问",
"name": "11b3c4dbc8424171b09cc3d0f280f4bb",
"id": 227
},
{
"password": "ea72db827a9247b19fe643b0c489b0aa",
"code": "925",
"user_name": "吕先真",
"name": "ef0ba32ee43e485bb476fa197d24a747",
"id": 925
},
{
"password": "d905182a2d394ade8d49193e9de9c582",
"code": "1782",
"user_name": "李十问",
"name": "0ea6786b036f47f2a2c42973fa12139a",
"id": 1782
}
]
```
### 缓存
只缓存SSRDynamicSQL表的查询数据。
#### 内置缓存
* 内部实现的缓存
* ehcache
* redis
* 使用
需要手动添加配置,指定使用的缓存,例如使用redis:ssr.cache.type=redis
#### 自定义缓存
* 实现接口SSRCache
* 加上注解`@Component`交给spring管理
* 也可以添加上配置条件,加上注解`@ConditionalOnProperty(prefix = "ssr", name = "cache.type", havingValue = "自定义缓存key")`
### orm框架
#### MyBatis
#### hibernate
#### 自定义orm框架
* 主要是实现接口QueryORM,也可以同时实现接口QueryORM跟继承AbstractQueryORM,AbstractQueryORM类默认实现了一些方法,不需要再实现。
* 加上注解`@Component`交给spring管理
### 自定义SSRDynamicSQL表名
可以添加配置:ssr.dynamicSql.TableName=自定义SSRDynamicSQL表名
### bean说明文档
#### QueryParams
|属性名|属性类型|属性意思|是否必填|
|-----|-------|-------|------|
|queryCode|String|对应数据库里的QUERY_CODE。如是自动生成sql模式,格式为[表名/类名全名]:[generateByTable/generateByEntity]:[数据源的名称]|必填|
|params|Map|查询参数。key为sql里的占位符,value为值|非必填|
|sort|LinkedHashMap|排序。key为排序的字段,value为正序或者倒序|非必填|
|queryResultModel|boolean|是否返回封装类型。true为查询结果返回QueryResult封装的结果集|非必填|
|generateSort|boolean|是否生成排序。如果为false。则设置了sort属性也不会排序。|非必填|
|condition|List|自动生成sql where 条件用。因为是自动生成sql语句,所以查询条件需要通过此参数来设置。|非必填|
|selectFields|String|自动生成sql用,查询字段,多个用英文逗号分隔。默认为*。|非必填|
|pageNo|int|分页用,第几页。|非必填|
|pageSize|int|分页用,一页多少条。-1则为查询全部。|非必填|
|generatePage|boolean|是否生成分页。默认为true。|非必填|
#### QueryCondition
|属性名|属性类型|属性意思|是否必填|
|-----|-------|-------|------|
|fieldName|String|查询条件的字段名|必填|
|value|Object|查询条件的值|必填|
|logicalOperator|String|逻辑运算符|非必填。取值例如:AND OR 等|
|relationalOperator|String|关系运算符|非必填。取值例如:like = != > < >= >= 等|
|condition|QueryCondition|分组查询条件|非必填|
#### QueryInfo
|属性名|属性类型|属性意思|是否必填|
|-----|-------|-------|------|
|querySQL|QuerySQL|查询的sql分组类|非必填|
|queryStartTime|Long|查询开始时间|非必填|
|queryEndTime|Long|查询结束时间|非必填|
#### QueryResult
|属性名|属性类型|属性意思|是否必填|
|-----|-------|-------|------|
|result|Object|查询结果集|必填|
|code|Integer|查询状态码|必填|
|message|String|查询响应信息|必填|
#### QueryRule
|属性名|属性类型|属性意思|是否必填|
|-----|-------|-------|------|
|queryCode|String|查询code|必填|
|dynamicSql|SSRDynamicSQL|SSRDynamicSQL|非必填|
|queryCodeType|QueryCodeType|查询规则类型|必填|
|queryCodeMap|Map|查询规则|非必填|
#### QuerySQL
|属性名|属性类型|属性意思|是否必填|
|-----|-------|-------|------|
|processedSQL|String|查理过sql|非必填|
|executeSQL|String|当前执行的SQL|非必填|
|simpleSQL|String|原SQL|必填|
#### SSRDynamicSQL
|属性名|属性类型|属性意思|是否必填|
|-----|-------|-------|------|
|id|String|主键|是|
|queryCode|String|查询的code。不允许使用英文逗号“,”跟冒号“:”|是|
|queryName|String|查询的名称|否|
|queryType|String|查询的类型|否|
|dataSourceName|String|数据源名称|否|
|sqlTemplate|String|sql模板|否|
|resultType|String|返回类型,多个用逗号分割。queryCode:class name|否|
|beforeScript|String|查询之前处理脚本|否|
|afterScript|String|查询之后处理脚本|否|
|version|Integer|版本号|否|
|delFlag|Integer|是否删除。1:是,0:否|否|
|orderNum|Integer|排序编号。正序。|否|
|createName|String|创建人名称|否|
|createId|String|创建人id|否|
|createTime|Date|创建时间|否|
|updateName|String|修改人名称|否|
|updateId|String|修改人id|否|
|updateTime|Date|修改时间|否|
|String|remark|备注|否|
#### Query
```
/**
* 查询返回Object
*
* @param queryParams 查询参数
* @return Class clazz 转换的类型
*/
Object query(QueryParams queryParams, Class clazz);
/**
* 查询返回Object
*
* @param queryParams 查询参数
*/
Object query(QueryParams queryParams);
/**
* 查询返回map list
*
* @param queryParams 查询参数
* @return map的集合
*/
List