# 通用API接口 **Repository Path**: wb04307201/mybatis-api ## Basic Information - **Project Name**: 通用API接口 - **Description**: MyBatis API 是一个基于 MyBatis 的通用数据访问层框架,提供了通过 JSON 参数动态构建 SQL 语句的能力。该项目允许开发者通过简单的 JSON 配置来执行常见的数据库操作(增删改查),而无需编写具体的 Mapper XML 文件。 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 15 - **Forks**: 1 - **Created**: 2022-11-24 - **Last Updated**: 2025-08-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Mybatis API - 通用 API 接口 > MyBatis API 是一个基于 MyBatis 的通用数据访问层框架,提供了通过 JSON 参数动态构建 SQL 语句的能力。该项目允许开发者通过简单的 JSON 配置来执行常见的数据库操作(增删改查),而无需编写具体的 Mapper XML 文件。 [![](https://jitpack.io/v/com.gitee.wb04307201/mybatis-api.svg)](https://jitpack.io/#com.gitee.wb04307201/mybatis-api) [![star](https://gitee.com/wb04307201/mybatis-api/badge/star.svg?theme=dark)](https://gitee.com/wb04307201/mybatis-api) [![fork](https://gitee.com/wb04307201/mybatis-api/badge/fork.svg?theme=dark)](https://gitee.com/wb04307201/mybatis-api) [![star](https://img.shields.io/github/stars/wb04307201/mybatis-api)](https://github.com/wb04307201/mybatis-api) [![fork](https://img.shields.io/github/forks/wb04307201/mybatis-api)](https://github.com/wb04307201/mybatis-api) ![MIT](https://img.shields.io/badge/License-Apache2.0-blue.svg) ![JDK](https://img.shields.io/badge/JDK-17+-green.svg) ![SpringBoot](https://img.shields.io/badge/Srping%20Boot-3+-green.svg) ## 功能特性 - **通用 CRUD 操作**:支持通过 JSON 参数执行 select、insert、update、delete 操作 - **动态 SQL 构建**:自动构建 SQL 语句,支持连接查询、排序、分组、去重等操作 - **分页查询**:内置分页支持,自动计算分页参数 - **安全机制**:集成 SQL 注入检查,防止恶意 SQL 注入攻击 - **灵活扩展**:支持自定义 ID 生成策略、字段映射策略和结果处理策略 - **事务支持**:所有操作均在事务中执行,确保数据一致性 * ## [1.如何使用](#1) * ## [2.语法 ](#2) * #### [2.1 新增](#2.1) * ###### [2.1.1 新增单条数据](#2.1.1) * ###### [2.1.2 新增批量数据](#2.1.2) * ###### [2.1.3 新增后按照查询返回数据](#2.1.3) * #### [2.2 修改](#2.2) * ###### [2.2.1 按照一个查询结果修改数据](#2.2.1) * ###### [2.2.2 按照多个查询结果修改数](#2.2.2) * ###### [2.2.3 修改后按照查询返回数据](#2.2.3) * #### [2.3 新增或修改](#2.3) * ###### [2.3.1 单条数据](#2.3.1) * ###### [2.3.2 批量数据](#2.3.2) * ###### [2.3.3 如何自定义主键名称](#2.3.3) * ###### [2.3.4 如何自定义生成主键值](#2.3.4) * #### [2.4 查询](#2.4) * ###### [2.4.1 单表查询](#2.4.1) * ###### [2.4.2 分页查询](#2.4.2) * ###### [2.4.3 多表关联查询](#2.4.3) * ###### [2.4.4 分组查询](#2.4.4) * ###### [2.4.5 去重和排序](#2.4.5) * ###### [2.4.6 自定义结果集映射](#2.4.6) * #### [2.5 删除](#2.5) * #### [2.6 groovy](#2.6) * #### [2.7 请求基础路径](#2.7) * #### [2.8 自定义响应格式](#2.8) * #### [2.9 其他使用的方式](#2.9) ##

1.如何使用

#### 第一步 增加 JitPack 仓库 ```xml jitpack.io https://jitpack.io ``` #### 第二步 引入jar ```xml com.gitee.wb04307201.mybatis-api mybatis-api-spring-boot-starter 1.1.4 ``` #### 第三步 记得配置数据库信息,例如 ```yaml spring: datasource: url: jdbc:h2:mem:testdb driverClassName: org.h2.Driver username: sa password: ``` **启动项目,试试通过接口访问数据库吧** --- ##

2.语法

####

2.1 新增

> 请求地址 http://ip:port/api/insert/{tableName} ######

2.1.1 新增单条数据

请求体 ```json { "code": "11111", "name": "11111" } ``` 响应 ```json 1 ``` ######

2.1.2 新增批量数据

请求体 ```json [ { "code": "11111", "name": "11111" }, { "code": "22222", "name": "22222" } ] ``` 响应: ```json 2 ``` ######

2.1.3 新增后按照查询返回数据

可使用@with_select添加查询条件返回数据 请求体 ```json { "id": "id-test-001", "code": "11111", "name": "11111", "@with_select": { "@column": "id,code,name", "@where": [ { "key": "id", "value": "id-test-001" } ] } } ``` 响应 ```json [ { "code": "11111", "id": "id-test-001", "name": "11111" } ] ``` ##

2.2 修改

> 根据查询条件修改数据 > 请求地址 http://ip:port/api/update/{tableName} ######

2.2.1 按照一个查询结果修改数据

请求体 ```json { "code": "33333", "name": "33333", "@where": [ { "key": "id", "condition": "eq", "value": "417f6982-0e16-45cc-b1d4-51aa070c74d8" } ] } ``` 响应: ```json 1 ``` ######

2.2.2 按照多个查询结果修改数据

请求体 ```json [ { "code": "33333", "name": "33333", "@where": [ { "key": "id", "condition": "eq", "value": "417f6982-0e16-45cc-b1d4-51aa070c74d8" } ] }, { "code": "4444", "name": "4444", "@where": [ { "key": "id", "condition": "eq", "value": "001-001-001" } ] } ] ``` 响应: ```json [ 1, 1 ] ``` ######

2.2.3 修改后按照查询返回数据

可使用@with_select添加查询条件返回数据 请求体 ```json { "code": "33333", "name": "33333", "@where": [ { "key": "id", "condition": "eq", "value": "417f6982-0e16-45cc-b1d4-51aa070c74d8" } ], "@with_select": { "@column": "id,code,name", "@where": [ { "key": "id", "value": "417f6982-0e16-45cc-b1d4-51aa070c74d8" } ] } } ``` 响应: ```json [ { "code": "33333", "id": "417f6982-0e16-45cc-b1d4-51aa070c74d8", "name": "33333" } ] ``` ##

2.3 新增或修改

> 请求体包含id则根据id修改数据,不包含id则生成id新增数据 > 请求地址 http://ip:port/api/inertOrUpdate/{tableName} ######

2.3.1 单条数据

请求体 ```json { "code": "11111", "name": "11111" } ``` 响应 ```json { "code": "22222", "id": "d89cbafc-cf9f-445a-89fa-9cc53f8b55b8", "name": "22222" } ``` ######

2.3.2 批量数据

请求体 ```json [ { "code": "11111", "name": "11111" }, { "name": "33333", "id": "d89cbafc-cf9f-445a-89fa-9cc53f8b55b8" } ] ``` 响应 ```json [ { "code": "11111", "id": "417f6982-0e16-45cc-b1d4-51aa070c74d8", "name": "11111" }, { "code": "22222", "id": "d89cbafc-cf9f-445a-89fa-9cc53f8b55b8", "name": "33333" } ] ``` ######

2.3.3 如何自定义主键名称

```yaml mybatis: api: id: id #数据库主键名称,默认为id ``` ######

2.3.4 如何自定义生成主键值

继承IDService接口后实现generalID方法,并注册bean ```java @Component public class SnowflakeIdServiceImpl implements IDService { // ==============================Fields=========================================== /** * 开始时间截 (2015-01-01) */ private final long twepoch = 1489111610226L; /** * 机器id所占的位数 */ private final long workerIdBits = 5L; /** * 数据标识id所占的位数 */ private final long dataCenterIdBits = 5L; /** * 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */ private final long maxWorkerId = -1L ^ (-1L << workerIdBits); /** * 支持的最大数据标识id,结果是31 */ private final long maxDataCenterId = -1L ^ (-1L << dataCenterIdBits); /** * 序列在id中占的位数 */ private final long sequenceBits = 12L; /** * 机器ID向左移12位 */ private final long workerIdShift = sequenceBits; /** * 数据标识id向左移17位(12+5) */ private final long dataCenterIdShift = sequenceBits + workerIdBits; /** * 时间截向左移22位(5+5+12) */ private final long timestampLeftShift = sequenceBits + workerIdBits + dataCenterIdBits; /** * 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */ private final long sequenceMask = -1L ^ (-1L << sequenceBits); /** * 工作机器ID(0~31) */ private long workerId; /** * 数据中心ID(0~31) */ private long dataCenterId; /** * 毫秒内序列(0~4095) */ private long sequence = 0L; /** * 上次生成ID的时间截 */ private long lastTimestamp = -1L; //==============================Constructors===================================== public cn.wubo.mybatis.api.SnowflakeIdServiceImpl() { this.workerId = 0L; this.dataCenterId = 0L; } /** * 构造函数 * * @param workerId 工作ID (0~31) * @param dataCenterId 数据中心ID (0~31) */ public cn.wubo.mybatis.api.SnowflakeIdServiceImpl(long workerId, long dataCenterId) { if (workerId > maxWorkerId || workerId < 0) { throw new IllegalArgumentException(String.format("workerId can't be greater than %d or less than 0", maxWorkerId)); } if (dataCenterId > maxDataCenterId || dataCenterId < 0) { throw new IllegalArgumentException(String.format("dataCenterId can't be greater than %d or less than 0", maxDataCenterId)); } this.workerId = workerId; this.dataCenterId = dataCenterId; } // ==============================Methods========================================== /** * 获得下一个ID (该方法是线程安全的) * * @return SnowflakeId */ @Override public synchronized Long generalID() { long timestamp = timeGen(); //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常 if (timestamp < lastTimestamp) { throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); } //如果是同一时间生成的,则进行毫秒内序列 if (lastTimestamp == timestamp) { sequence = (sequence + 1) & sequenceMask; //毫秒内序列溢出 if (sequence == 0) { //阻塞到下一个毫秒,获得新的时间戳 timestamp = tilNextMillis(lastTimestamp); } } //时间戳改变,毫秒内序列重置 else { sequence = 0L; } //上次生成ID的时间截 lastTimestamp = timestamp; //移位并通过或运算拼到一起组成64位的ID return ((timestamp - twepoch) << timestampLeftShift) // | (dataCenterId << dataCenterIdShift) // | (workerId << workerIdShift) // | sequence; } /** * 阻塞到下一个毫秒,直到获得新的时间戳 * * @param lastTimestamp 上次生成ID的时间截 * @return 当前时间戳 */ protected long tilNextMillis(long lastTimestamp) { long timestamp = timeGen(); while (timestamp <= lastTimestamp) { timestamp = timeGen(); } return timestamp; } /** * 返回以毫秒为单位的当前时间 * * @return 当前时间(毫秒) */ protected long timeGen() { return System.currentTimeMillis(); } } ``` ##

2.4 查询

> 请求地址 http://ip:port/api/select/{tableName} ######

2.4.1 单表查询

请求体 ```json { "@column": "id,name", "@where": [ { "key": "id", "condition": "notnull" } ] } ``` 响应 ```json [ { "id": "001", "name": "name1" }, { "id": "417f6982-0e16-45cc-b1d4-51aa070c74d8", "name": "33333" }, { "id": "d89cbafc-cf9f-445a-89fa-9cc53f8b55b8", "name": "22222" } ] ``` ######

2.4.2 分页查询

请求体 ```json { "@where": [ { "key": "id", "condition": "notnull" } ], "@page": { "pageIndex": 0, "pageSize": 10 } } ``` 响应 ```json { "total": 4, "pageSize": 10, "pageIndex": 0, "records": [ { "code": "22", "name": "22", "person_memo": "1", "id": 872320795374780416 }, { "code": "11111", "name": "11111", "person_memo": "2", "id": 872320851729448960 }, { "code": "11111", "name": "11111", "person_memo": "3", "id": 872320854896148480 }, { "code": "11111", "name": "11111", "person_memo": "4", "id": 872320858343866368 } ] } ``` ######

2.4.3 多表关联查询

请求体 ```json { "@column": "person.id,person.name,person.deptcode,dept.name as deptname", "@where": [ { "key": "person.id", "condition": "notnull" } ], "@join": { "join": "dept on person.deptcode = dept.code" } } ``` 响应 ```json [ { "deptcode": "deptcode1", "id": "001", "name": "name1", "deptname": "deptname1" } ] ``` > @join支持join,inner_join,left_outer_join,right_outer_join,outer_join > @where condition支持eq,ueq,like,ulike,llike,rlike,gt,lt,gteq,lteq,between,notbetween,in,notin,null,notnull ######

2.4.4 分组查询

请求体 ```json { "@column": "deptcode,count(1) as personcount", "@where": [ { "key": "id", "condition": "notnull" } ], "@group": [ "deptcode" ] } ``` 响应 ```json [ { "deptcode": "deptcode1", "personcount": "2" } ] ``` ######

2.4.5 去重和排序

```http request POST http://localhost:8080/api/select/sys_user Content-Type: application/json { "@column": "name,code", "@where":[ { "key": "id", "condition": "notnull" } ], "@distinct": true, "@order":["code desc"] } ``` ######

2.4.6 自定义结果集映射

集成IMappingService接口并实现parseKey方法 ```java @Component public class CamelCaseMappingServiceImpl implements IMappingService { @Override public String parseKey(String field) { String[] words = field.split("[-_]"); return Arrays.stream(words, 1, words.length).map(s -> s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase()).reduce(words[0].toLowerCase(), String::concat); } } ``` ##

2.5 删除

> 请求地址 http://ip:port/api/delete/{tableName} 请求体 ```json { "@where": [ { "key": "id", "condition": "in", "value": [ "417f6982-0e16-45cc-b1d4-51aa070c74d8", "d89cbafc-cf9f-445a-89fa-9cc53f8b55b8" ] } ] } ``` 响应 ```json 2 ``` ##

2.6 groovy

传递值支持groovy代码,key以"(G)”结尾,value用groovy代码构成,注意要有返回值,例如 ```http request POST http://localhost:8080/api/insertOrUpdate/sys_user Content-Type: application/json { "name": "name", "code": "code", "password": "password", "user_type": "super", "create_time(G)":"import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;return LocalDateTime.now().format(DateTimeFormatter.ofPattern('yyyy-MM-dd'))" } ``` ##

2.7 请求基础路径

```yaml mybatis: api: basePath: /api #访问接口基础路径,默认为/api ``` ##

2.8 自定义响应格式

继承IResultService接口后实现generalResult方法,并注册bean ```java @Component public class ResponseResultServiceImpl implements IResultService> { @Override public ResponseEntity generalResult(Object o) { return ResponseEntity.ok(o); } } ``` ##

2.9 其他使用的方式

```java // 注入MyBatisApiService @Autowired MyBatisApiService myBatisApiService; // 通过myBatisApiService调用方法 myBatisApiService.insertParse myBatisApiService.updateParse myBatisApiService.insertOrUpdateParse myBatisApiService.deleteParse myBatisApiService.selectParse ```