{"id":21803011,"url":"https://github.com/litongjava/api-table","last_synced_at":"2025-03-21T07:16:01.075Z","repository":{"id":170977461,"uuid":"647218215","full_name":"litongjava/api-table","owner":"litongjava","description":"Java DB 框架,自动完成table转Json","archived":false,"fork":false,"pushed_at":"2025-03-15T11:14:36.000Z","size":5149,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-15T12:22:32.528Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/litongjava.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-30T10:03:04.000Z","updated_at":"2025-03-15T11:14:40.000Z","dependencies_parsed_at":"2023-07-10T03:15:20.229Z","dependency_job_id":"5e7db0f7-b63a-4074-a0ab-dfa0fd2c4a47","html_url":"https://github.com/litongjava/api-table","commit_stats":null,"previous_names":["litongjava/table-to-json"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/litongjava%2Fapi-table","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/litongjava%2Fapi-table/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/litongjava%2Fapi-table/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/litongjava%2Fapi-table/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/litongjava","download_url":"https://codeload.github.com/litongjava/api-table/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244752362,"owners_count":20504256,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-11-27T11:37:05.246Z","updated_at":"2025-03-21T07:16:01.047Z","avatar_url":"https://github.com/litongjava.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ApiTable\n\n在现代应用开发中，简化数据库操作、提高代码复用性和维护性是每个开发者追求的目标。**ApiTable** 作为一个基于 **java-db** 框架的通用数据表操作工具，旨在实现这一目标。本文将详细介绍如何封装 **ApiTableService** 以及如何在控制器中使用 **ApiTableService**，以实现高效、灵活的增删改查（CRUD）操作。\n\n## 目录\n\n1. [前言](#前言)\n2. [项目结构与依赖配置](#项目结构与依赖配置)\n3. [封装 ApiTableService](#封装-apitableservice)\n4. [创建 ApiPostController](#创建-apipostcontroller)\n5. [使用 ApiTableService](#使用-apitableservice)\n6. [测试接口](#测试接口)\n7. [总结](#总结)\n\n## 前言\n\n在实际开发过程中，频繁的数据库操作往往导致大量重复代码的出现，增加了维护难度。通过封装 **ApiTableService**，可以将常用的数据库操作集中管理，提升代码的可读性和可维护性。同时，结合 **tio-boot** 框架的特性，可以进一步简化开发流程，实现高效的接口管理。\n\n## 项目结构与依赖配置\n\n在开始封装 **ApiTableService** 之前，确保项目已经正确配置了所需的依赖。以下是 `pom.xml` 文件中需要添加的依赖项：\n\n```xml\n\u003cdependencies\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003ecom.alibaba.fastjson2\u003c/groupId\u003e\n    \u003cartifactId\u003efastjson2\u003c/artifactId\u003e\n    \u003cversion\u003e2.0.12\u003c/version\u003e\n  \u003c/dependency\u003e\n\n  \u003cdependency\u003e\n    \u003cgroupId\u003ecom.litongjava\u003c/groupId\u003e\n    \u003cartifactId\u003etio-boot\u003c/artifactId\u003e\n    \u003cversion\u003e${tio.boot.version}\u003c/version\u003e\n  \u003c/dependency\u003e\n\n  \u003cdependency\u003e\n    \u003cgroupId\u003ecom.litongjava\u003c/groupId\u003e\n    \u003cartifactId\u003eapi-table\u003c/artifactId\u003e\n    \u003cversion\u003e${tio.boot.version}\u003c/version\u003e\n  \u003c/dependency\u003e\n\n  \u003cdependency\u003e\n    \u003cgroupId\u003ecom.alibaba\u003c/groupId\u003e\n    \u003cartifactId\u003eeasyexcel\u003c/artifactId\u003e\n    \u003cversion\u003e2.2.10\u003c/version\u003e\n  \u003c/dependency\u003e\n\n  \u003c!-- 连接池 --\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003ecom.alibaba\u003c/groupId\u003e\n    \u003cartifactId\u003edruid\u003c/artifactId\u003e\n    \u003cversion\u003e1.1.10\u003c/version\u003e\n  \u003c/dependency\u003e\n\n  \u003c!-- 数据库驱动 --\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003emysql\u003c/groupId\u003e\n    \u003cartifactId\u003emysql-connector-java\u003c/artifactId\u003e\n    \u003cversion\u003e5.1.46\u003c/version\u003e\n  \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\n请确保所有依赖的版本号为最新版本，以获得最佳的功能和安全性。\n\n## 封装 ApiTableService\n\n**ApiTableService** 是封装 **ApiTable** 操作的核心服务类，负责处理与数据库表相关的所有增删改查操作。通过统一的接口，简化了控制器中的代码逻辑。\n\n### ApiTableService 代码\n\n以下是 **ApiTableService** 的完整代码：\n\n```java\npackage com.litongjava.max.blog.service;\n\nimport java.io.IOException;\nimport java.sql.SQLException;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.jfinal.kit.Kv;\nimport com.litongjava.db.TableInput;\nimport com.litongjava.db.TableResult;\nimport com.litongjava.db.activerecord.Db;\nimport com.litongjava.db.activerecord.Record;\nimport com.litongjava.model.body.RespBodyVo;\nimport com.litongjava.model.page.DbPage;\nimport com.litongjava.model.page.Page;\nimport com.litongjava.table.services.ApiTable;\nimport com.litongjava.table.utils.EasyExcelResponseUtils;\nimport com.litongjava.table.utils.TableInputUtils;\nimport com.litongjava.table.utils.TableResultUtils;\nimport com.litongjava.tio.boot.http.TioRequestContext;\nimport com.litongjava.tio.boot.utils.TioRequestParamUtils;\nimport com.litongjava.tio.http.common.HttpRequest;\nimport com.litongjava.tio.http.common.HttpResponse;\n\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\npublic class ApiTableService {\n\n  public RespBodyVo create(String f, HttpRequest request) {\n    Map\u003cString, Object\u003e map = TioRequestParamUtils.getRequestMap(request);\n    map.remove(\"f\");\n    ApiTable.transformType(f, map);\n    TableInput kv = TableInputUtils.camelToUnderscore(map);\n    log.info(\"tableName:{},kv:{}\", f, kv);\n    TableResult\u003cKv\u003e dbJsonBean = ApiTable.saveOrUpdate(f, kv);\n    if (dbJsonBean.getCode() == 1) {\n      return RespBodyVo.ok(dbJsonBean.getData()).code(dbJsonBean.getCode()).msg(dbJsonBean.getMsg());\n    } else {\n      return RespBodyVo.fail(dbJsonBean.getMsg()).code(dbJsonBean.getCode()).data(dbJsonBean.getData());\n    }\n  }\n\n  public RespBodyVo list(String f, HttpRequest request) {\n    Map\u003cString, Object\u003e map = TioRequestParamUtils.getRequestMap(request);\n    map.remove(\"f\");\n    ApiTable.transformType(f, map);\n    TableInput kv = TableInputUtils.camelToUnderscore(map);\n\n    log.info(\"tableName:{},kv:{}\", f, kv);\n    TableResult\u003cList\u003cRecord\u003e\u003e list = ApiTable.list(f, kv);\n\n    TableResult\u003cList\u003cKv\u003e\u003e dbJsonBean = TableResultUtils.recordsToKv(list, false);\n\n    return RespBodyVo.ok(dbJsonBean.getData()).code(dbJsonBean.getCode()).msg(dbJsonBean.getMsg());\n  }\n\n  public RespBodyVo listAll(String f) {\n    log.info(\"tableName:{}\", f);\n    TableResult\u003cList\u003cRecord\u003e\u003e listAll = ApiTable.listAll(f);\n    TableResult\u003cList\u003cKv\u003e\u003e dbJsonBean = TableResultUtils.recordsToKv(listAll, false);\n\n    return RespBodyVo.ok(dbJsonBean.getData()).code(dbJsonBean.getCode()).msg(dbJsonBean.getMsg());\n  }\n\n  public RespBodyVo page(String f, HttpRequest request) {\n    Map\u003cString, Object\u003e map = TioRequestParamUtils.getRequestMap(request);\n    map.remove(\"f\");\n    Object current = map.remove(\"current\");\n    if (current != null) {\n      // 支持 Ant Design Pro Table\n      map.put(\"pageNo\", current);\n    }\n\n    ApiTable.transformType(f, map);\n\n    TableInput kv = TableInputUtils.camelToUnderscore(map);\n\n    log.info(\"tableName:{},kv:{}\", f, kv);\n    TableResult\u003cPage\u003cRecord\u003e\u003e page = ApiTable.page(f, kv);\n\n    TableResult\u003cDbPage\u003cKv\u003e\u003e dbJsonBean = TableResultUtils.pageToDbPage(page, false);\n    return RespBodyVo.ok(dbJsonBean.getData()).code(dbJsonBean.getCode()).msg(dbJsonBean.getMsg());\n  }\n\n  public RespBodyVo get(String f, HttpRequest request) {\n    Map\u003cString, Object\u003e map = TioRequestParamUtils.getRequestMap(request);\n    map.remove(\"f\");\n    ApiTable.transformType(f, map);\n    TableInput kv = TableInputUtils.camelToUnderscore(map);\n\n    log.info(\"tableName:{},kv:{}\", f, kv);\n    TableResult\u003cRecord\u003e jsonBean = ApiTable.get(f, kv);\n    TableResult\u003cKv\u003e dbJsonBean = TableResultUtils.recordToKv(jsonBean);\n\n    return RespBodyVo.ok(dbJsonBean.getData()).code(dbJsonBean.getCode()).msg(dbJsonBean.getMsg());\n  }\n\n  public RespBodyVo update(String f, HttpRequest request) {\n    Map\u003cString, Object\u003e map = TioRequestParamUtils.getRequestMap(request);\n    map.remove(\"f\");\n    ApiTable.transformType(f, map);\n    TableInput kv = TableInputUtils.camelToUnderscore(map);\n\n    log.info(\"tableName:{},kv:{}\", f, kv);\n    TableResult\u003cKv\u003e dbJsonBean = ApiTable.saveOrUpdate(f, kv);\n\n    return RespBodyVo.ok(dbJsonBean.getData()).code(dbJsonBean.getCode()).msg(dbJsonBean.getMsg());\n  }\n\n  public RespBodyVo batchUpdate(String f, HttpRequest request) {\n    Map\u003cString, Object\u003e map = TioRequestParamUtils.getRequestMap(request);\n    map.remove(\"f\");\n    ApiTable.transformType(f, map);\n    TableInput kv = TableInputUtils.camelToUnderscore(map);\n\n    log.info(\"tableName:{},kv:{}\", f, kv);\n    TableResult\u003cKv\u003e dbJsonBean = ApiTable.batchUpdateByIds(f, kv);\n\n    return RespBodyVo.ok(dbJsonBean.getData()).code(dbJsonBean.getCode()).msg(dbJsonBean.getMsg());\n  }\n\n  public RespBodyVo remove(String f, String id) {\n    log.info(\"tableName:{},id:{}\", f, id);\n    TableResult\u003cBoolean\u003e dbJsonBean = ApiTable.updateFlagById(f, id, \"deleted\", 1);\n    return RespBodyVo.ok(dbJsonBean.getData()).code(dbJsonBean.getCode()).msg(dbJsonBean.getMsg());\n  }\n\n  public RespBodyVo delete(String f, String id) {\n    log.info(\"tableName:{},id:{}\", f, id);\n    TableResult\u003cBoolean\u003e dbJsonBean = ApiTable.delById(f, id);\n    return RespBodyVo.ok(dbJsonBean.getData()).code(dbJsonBean.getCode()).msg(dbJsonBean.getMsg());\n  }\n\n  public RespBodyVo total(String f) {\n    log.info(\"tableName:{},id:{}\", f);\n    Long count = Db.count(f);\n    return RespBodyVo.ok(count);\n  }\n\n  public HttpResponse exportExcel(String f, HttpRequest request) throws IOException {\n    Map\u003cString, Object\u003e map = TioRequestParamUtils.getRequestMap(request);\n    map.remove(\"f\");\n    ApiTable.transformType(f, map);\n    Object current = map.remove(\"current\");\n    if (current != null) {\n      // 支持 Ant Design Pro Table\n      map.put(\"pageNo\", current);\n    }\n    TableInput kv = TableInputUtils.camelToUnderscore(map);\n\n    log.info(\"tableName:{},kv:{}\", f, kv);\n    String filename = f + \"_export_\" + System.currentTimeMillis() + \".xlsx\";\n\n    // 获取数据\n    List\u003cRecord\u003e records = ApiTable.list(f, kv).getData();\n    HttpResponse response = TioRequestContext.getResponse();\n    return EasyExcelResponseUtils.exportRecords(response, filename, f, records);\n  }\n\n  public HttpResponse exportAllExcel(String f, HttpRequest request) throws IOException, SQLException {\n    Map\u003cString, Object\u003e map = TioRequestParamUtils.getRequestMap(request);\n    map.remove(\"f\");\n    map.remove(\"current\");\n    map.remove(\"pageNo\");\n    map.remove(\"pageSize\");\n    ApiTable.transformType(f, map);\n\n    TableInput kv = TableInputUtils.camelToUnderscore(map);\n\n    log.info(\"tableName:{},kv:{}\", f, kv);\n\n    // 导出 Excel\n    String filename = f + \"-all_\" + System.currentTimeMillis() + \".xlsx\";\n\n    // 获取数据\n    List\u003cRecord\u003e records = ApiTable.listAll(f, kv).getData();\n\n    HttpResponse response = TioRequestContext.getResponse();\n    EasyExcelResponseUtils.exportRecords(response, filename, f, records);\n    log.info(\"finished\");\n    return response;\n  }\n\n  public HttpResponse exportAllTableExcel(HttpRequest request) throws IOException {\n    String filename = \"all-table_\" + System.currentTimeMillis() + \".xlsx\";\n    String[] tables = ApiTable.getAllTableNames();\n    LinkedHashMap\u003cString, List\u003cRecord\u003e\u003e allTableData = new LinkedHashMap\u003c\u003e();\n\n    for (String table : tables) {\n      // 获取数据\n      List\u003cRecord\u003e records = ApiTable.listAll(table).getData();\n      allTableData.put(table, records);\n    }\n    HttpResponse response = TioRequestContext.getResponse();\n    EasyExcelResponseUtils.exportAllTableRecords(response, filename, allTableData);\n    log.info(\"finished\");\n    return response;\n  }\n\n  public RespBodyVo pageDeleted(String f, HttpRequest request) {\n    Map\u003cString, Object\u003e map = TioRequestParamUtils.getRequestMap(request);\n    map.remove(\"f\");\n    ApiTable.transformType(f, map);\n    TableInput kv = TableInputUtils.camelToUnderscore(map);\n\n    log.info(\"tableName:{},kv:{}\", f, kv);\n    TableResult\u003cDbPage\u003cKv\u003e\u003e dbJsonBean = TableResultUtils.pageToDbPage(ApiTable.page(f, kv), false);\n\n    return RespBodyVo.ok(dbJsonBean.getData()).code(dbJsonBean.getCode()).msg(dbJsonBean.getMsg());\n  }\n\n  public RespBodyVo recover(String f, String id) {\n    log.info(\"tableName:{},id:{}\", f, id);\n    TableResult\u003cBoolean\u003e dbJsonBean = ApiTable.updateFlagById(f, id, \"deleted\", 0);\n\n    return RespBodyVo.ok(dbJsonBean.getData()).code(dbJsonBean.getCode()).msg(dbJsonBean.getMsg());\n  }\n\n  public RespBodyVo tableNames() throws IOException {\n    String[] data = ApiTable.tableNames().getData();\n    return RespBodyVo.ok(data);\n  }\n\n  public RespBodyVo fConfig(String f, String lang) {\n    log.info(\"tableName:{}\", f);\n    TableResult\u003cMap\u003cString, Object\u003e\u003e dbJsonBean = ApiTable.tableConfig(f, f, lang);\n    return RespBodyVo.ok(dbJsonBean.getData()).code(dbJsonBean.getCode()).msg(dbJsonBean.getMsg());\n  }\n\n  public RespBodyVo proTableColumns(String f) {\n    TableResult\u003cList\u003cMap\u003cString, Object\u003e\u003e\u003e dbJsonBean = ApiTable.columns(f);\n    return RespBodyVo.ok(dbJsonBean.getData()).code(dbJsonBean.getCode()).msg(dbJsonBean.getMsg());\n  }\n}\n```\n\n### 主要方法解析\n\n1. **create**：用于创建新记录。接收请求参数，转换类型后调用 `ApiTable.saveOrUpdate` 方法保存数据。\n2. **list**：根据条件查询符合的记录列表。\n3. **listAll**：查询表中所有记录。\n4. **page**：实现分页查询，支持前端分页参数（如 `current`）。\n5. **get**：根据唯一条件（如主键）获取单条记录。\n6. **update**：根据主键更新单条记录。\n7. **batchUpdate**：批量更新多条记录。\n8. **remove**：逻辑删除，通过更新 `deleted` 字段标记记录。\n9. **delete**：物理删除，直接从数据库中移除记录。\n10. **total**：获取指定表的记录总数。\n11. **exportExcel**：导出当前查询的数据为 Excel 文件，不包含已删除的数据。\n12. **exportAllExcel**：导出符合条件的所有数据为 Excel 文件，包括逻辑删除的数据。\n13. **exportAllTableExcel**：导出数据库中所有表的数据为一个 Excel 文件。\n14. **pageDeleted**：分页查询已逻辑删除的数据。\n15. **recover**：恢复已逻辑删除的记录。\n16. **tableNames**：获取数据库中所有表名。\n17. **fConfig**：获取指定表的配置，用于前端展示等。\n18. **proTableColumns**：获取指定表的字段信息。\n\n## 创建 ApiPostController\n\n**ApiPostController** 作为控制器，负责处理前端发送的请求，并调用 **ApiTableService** 中对应的方法完成具体操作。以下是 **ApiPostController** 的完整代码：\n\n### ApiPostController 代码\n\n```java\npackage com.litongjava.max.blog.controller;\n\nimport java.io.IOException;\nimport java.sql.SQLException;\n\nimport com.litongjava.annotation.EnableCORS;\nimport com.litongjava.annotation.RequestPath;\nimport com.litongjava.db.activerecord.Db;\nimport com.litongjava.jfinal.aop.Aop;\nimport com.litongjava.max.blog.consts.TableNames;\nimport com.litongjava.max.blog.service.ApiTableService;\nimport com.litongjava.model.body.RespBodyVo;\nimport com.litongjava.tio.http.common.HttpRequest;\nimport com.litongjava.tio.http.common.HttpResponse;\n\nimport lombok.extern.slf4j.Slf4j;\n\n@RequestPath(\"/api/post\")\n@Slf4j\n@EnableCORS\npublic class ApiPostController {\n\n  ApiTableService apiTableService = Aop.get(ApiTableService.class);\n  String f = TableNames.tio_boot_admin_article;\n\n  @RequestPath(\"/index\")\n  public String index() {\n    return \"ApiPostController\";\n  }\n\n  @RequestPath(\"/create\")\n  public RespBodyVo create(HttpRequest request) {\n    return apiTableService.create(f, request);\n  }\n\n  @RequestPath(\"/list\")\n  public RespBodyVo list(HttpRequest request) {\n    return apiTableService.list(f, request);\n  }\n\n  @RequestPath(\"/listAll\")\n  public RespBodyVo listAll() {\n    return apiTableService.listAll(f);\n  }\n\n  @RequestPath(\"/page\")\n  public RespBodyVo page(HttpRequest request) {\n    return apiTableService.page(f, request);\n  }\n\n  @RequestPath(\"/get\")\n  public RespBodyVo get(HttpRequest request) {\n    return apiTableService.get(f, request);\n  }\n\n  @RequestPath(\"/update\")\n  public RespBodyVo update(HttpRequest request) {\n    return apiTableService.update(f, request);\n  }\n\n  @RequestPath(\"/batchUpdate\")\n  public RespBodyVo batchUpdate(HttpRequest request) {\n    return apiTableService.batchUpdate(f, request);\n  }\n\n  @RequestPath(\"/remove/{id}\")\n  public RespBodyVo remove(String id) {\n    return apiTableService.remove(f, id);\n  }\n\n  @RequestPath(\"/delete/{id}\")\n  public RespBodyVo delete(String id) {\n    return apiTableService.delete(f, id);\n  }\n\n  @RequestPath(\"/total\")\n  public RespBodyVo total(String f) {\n    log.info(\"tableName:{},id:{}\", f);\n    Long count = Db.count(f);\n    return RespBodyVo.ok(count);\n  }\n\n  /**\n   * 导出当前数据\n   */\n  @RequestPath(\"/export-excel\")\n  public HttpResponse exportExcel(HttpRequest request) throws IOException {\n    return apiTableService.exportExcel(f, request);\n  }\n\n  /**\n   * 导出所有数据\n   */\n  @RequestPath(\"/export-table-excel\")\n  public HttpResponse exportAllExcel(HttpRequest request) throws IOException, SQLException {\n    return apiTableService.exportAllExcel(f, request);\n  }\n\n  @RequestPath(\"/pageDeleted\")\n  public RespBodyVo pageDeleted(HttpRequest request) {\n    return apiTableService.pageDeleted(f, request);\n  }\n\n  @RequestPath(\"/recover\")\n  public RespBodyVo recover(String id) {\n    return apiTableService.recover(f, id);\n  }\n\n  @RequestPath(\"/config\")\n  public RespBodyVo fConfig(String lang) {\n    return apiTableService.fConfig(f, lang);\n  }\n\n  @RequestPath(\"/columns\")\n  public RespBodyVo proTableColumns(String f) {\n    return apiTableService.proTableColumns(f);\n  }\n}\n```\n\n### 主要方法解析\n\n1. **create**：处理创建新文章的请求。\n2. **list**：处理获取文章列表的请求。\n3. **listAll**：处理获取所有文章的请求。\n4. **page**：处理分页获取文章的请求。\n5. **get**：处理获取单篇文章详情的请求。\n6. **update**：处理更新文章的请求。\n7. **batchUpdate**：处理批量更新文章的请求。\n8. **remove**：处理逻辑删除文章的请求。\n9. **delete**：处理物理删除文章的请求。\n10. **total**：获取文章表的总记录数。\n11. **exportExcel**：导出当前查询的文章数据为 Excel 文件。\n12. **exportAllExcel**：导出符合条件的所有文章数据为 Excel 文件。\n13. **pageDeleted**：分页查询已逻辑删除的文章。\n14. **recover**：恢复已逻辑删除的文章。\n15. **fConfig**：获取文章表的配置，用于前端展示等。\n16. **proTableColumns**：获取文章表的字段信息。\n\n## 使用 ApiTableService\n\n通过 **ApiPostController**，前端可以发送 HTTP 请求来完成文章的增删改查操作，而控制器则通过 **ApiTableService** 来处理具体的业务逻辑。以下是使用流程的简要说明：\n\n1. **发送请求**：前端通过 HTTP 请求（如 POST、GET、DELETE）发送数据到相应的接口。\n2. **控制器处理**：**ApiPostController** 接收请求，并调用 **ApiTableService** 中对应的方法。\n3. **服务层操作**：**ApiTableService** 通过 **ApiTable** 提供的静态方法，执行数据库操作。\n4. **返回响应**：操作结果通过 **RespBodyVo** 封装后返回给前端。\n\n### 示例：创建新文章\n\n**前端请求**：\n\n- **请求方式**：POST\n- **URL**：`http://localhost:10051/api/post/create`\n- **请求体**：\n\n  ```json\n  {\n    \"title\": \"新文章标题\",\n    \"content\": \"这是文章的内容。\",\n    \"author\": \"admin\",\n    \"status\": \"published\"\n  }\n  ```\n\n**控制器处理**：\n\n1. **ApiPostController** 的 `create` 方法接收请求，并调用 **ApiTableService** 的 `create` 方法。\n2. **ApiTableService** 的 `create` 方法解析请求参数，转换字段名，并调用 **ApiTable.saveOrUpdate** 方法保存数据。\n3. 保存成功后，返回包含新记录 ID 的响应。\n\n**响应示例**：\n\n```json\n{\n  \"data\": {\n    \"id\": \"361177594135064576\"\n  },\n  \"code\": 1,\n  \"msg\": null,\n  \"ok\": true\n}\n```\n\n## 测试接口\n\n为了确保 **ApiTableService** 和 **ApiPostController** 的功能正常，需对各个接口进行详细测试。以下是各个接口的测试说明，包括请求方式、URL、参数及预期响应。\n\n### 测试 create\n\n- **功能**：添加一条新数据。\n- **请求方式**：POST\n- **URL**：`http://localhost:10051/api/post/create`\n- **请求体**：\n\n  ```json\n  {\n    \"title\": \"测试文章\",\n    \"content\": \"这是一篇测试文章。\",\n    \"author\": \"admin\",\n    \"status\": \"draft\"\n  }\n  ```\n\n- **响应示例**：\n\n  ```json\n  {\n    \"data\": {\n      \"id\": \"361177594135064576\"\n    },\n    \"code\": 1,\n    \"msg\": null,\n    \"ok\": true\n  }\n  ```\n\n### 测试 list\n\n- **功能**：查询文章列表。\n- **请求方式**：GET\n- **URL**：`http://localhost:10051/api/post/list`\n- **请求参数**：可选，如 `author=admin`。\n- **响应示例**：\n\n  ```json\n  {\n    \"data\": [\n      {\n        \"title\": \"测试文章\",\n        \"content\": \"这是一篇测试文章。\",\n        \"author\": \"admin\",\n        \"status\": \"draft\",\n        \"id\": \"361177594135064576\"\n      }\n      // 其他记录...\n    ],\n    \"msg\": null,\n    \"code\": 1,\n    \"ok\": true\n  }\n  ```\n\n### 测试 listAll\n\n- **功能**：查询所有文章。\n- **请求方式**：GET\n- **URL**：`http://localhost:10051/api/post/listAll`\n- **响应示例**：\n\n  ```json\n  {\n    \"data\": [\n      {\n        \"title\": \"测试文章\",\n        \"content\": \"这是一篇测试文章。\",\n        \"author\": \"admin\",\n        \"status\": \"draft\",\n        \"id\": \"361177594135064576\"\n      }\n      // 其他记录...\n    ],\n    \"code\": 1,\n    \"msg\": null,\n    \"ok\": true\n  }\n  ```\n\n### 测试 page\n\n- **功能**：分页查询文章。\n- **请求方式**：GET\n- **URL**：`http://localhost:10051/api/post/page`\n- **请求参数**：`current=1\u0026pageSize=10`\n- **响应示例**：\n\n  ```json\n  {\n    \"data\": {\n      \"total\": 17,\n      \"list\": [\n        {\n          \"title\": \"测试文章\",\n          \"content\": \"这是一篇测试文章。\",\n          \"author\": \"admin\",\n          \"status\": \"draft\",\n          \"id\": \"361177594135064576\"\n        }\n        // 其他记录...\n      ]\n    },\n    \"code\": 1,\n    \"msg\": null,\n    \"ok\": true\n  }\n  ```\n\n### 测试 get\n\n- **功能**：根据条件获取单条数据。\n- **请求方式**：GET\n- **URL**：`http://localhost:10051/api/post/get?title=测试文章`\n- **响应示例**：\n\n  ```json\n  {\n    \"data\": {\n      \"title\": \"测试文章\",\n      \"content\": \"这是一篇测试文章。\",\n      \"author\": \"admin\",\n      \"status\": \"draft\",\n      \"id\": \"361177594135064576\"\n    },\n    \"code\": 1,\n    \"msg\": null,\n    \"ok\": true\n  }\n  ```\n\n### 测试 update\n\n- **功能**：根据 ID 更新数据。\n- **请求方式**：POST\n- **URL**：`http://localhost:10051/api/post/update`\n- **请求体**：\n\n  ```json\n  {\n    \"id\": \"361177594135064576\",\n    \"title\": \"更新后的文章标题\",\n    \"status\": \"published\"\n  }\n  ```\n\n- **响应示例**：\n\n  ```json\n  {\n    \"data\": null,\n    \"code\": 1,\n    \"msg\": \"更新成功\",\n    \"ok\": true\n  }\n  ```\n\n### 测试 batchUpdate\n\n- **功能**：批量更新多条记录。\n- **请求方式**：POST\n- **URL**：`http://localhost:10051/api/post/batchUpdate`\n- **请求体**：\n\n  ```json\n  {\n    \"ids\": [\"361177594135064576\", \"361177594135064577\"],\n    \"status\": \"archived\"\n  }\n  ```\n\n- **响应示例**：\n\n  ```json\n  {\n    \"data\": null,\n    \"code\": 1,\n    \"msg\": \"批量更新成功\",\n    \"ok\": true\n  }\n  ```\n\n### 测试 remove\n\n- **功能**：逻辑删除数据。\n- **请求方式**：DELETE\n- **URL**：`http://localhost:10051/api/post/remove/361177594135064576`\n- **响应示例**：\n\n  ```json\n  {\n    \"data\": null,\n    \"code\": 1,\n    \"msg\": \"逻辑删除成功\",\n    \"ok\": true\n  }\n  ```\n\n### 测试 delete\n\n- **功能**：物理删除数据。\n- **请求方式**：DELETE\n- **URL**：`http://localhost:10051/api/post/delete/361177594135064576`\n- **响应示例**：\n\n  ```json\n  {\n    \"data\": null,\n    \"code\": 1,\n    \"msg\": \"删除成功\",\n    \"ok\": true\n  }\n  ```\n\n### 测试 total\n\n- **功能**：获取指定表的记录总数。\n- **请求方式**：GET\n- **URL**：`http://localhost:10051/api/post/total`\n- **响应示例**：\n\n  ```json\n  {\n    \"data\": 17,\n    \"code\": 1,\n    \"msg\": null,\n    \"ok\": true\n  }\n  ```\n\n### 测试 exportExcel\n\n- **功能**：导出当前查询的数据为 Excel 文件，不包含已删除的数据。\n- **请求方式**：GET\n- **URL**：`http://localhost:10051/api/post/export-excel`\n- **响应**：下载 `.xlsx` 文件。\n\n### 测试 exportAllExcel\n\n- **功能**：导出符合条件的所有数据为 Excel 文件，包括逻辑删除的数据。\n- **请求方式**：GET\n- **URL**：`http://localhost:10051/api/post/export-table-excel`\n- **响应**：下载 `.xlsx` 文件。\n\n### 测试 exportAllTableExcel\n\n- **功能**：导出数据库中所有表的数据为一个 Excel 文件，慎用。\n- **请求方式**：GET\n- **URL**：`http://localhost:10051/api/post/export-all-table-excel`\n- **响应**：下载 `.xlsx` 文件。\n\n### 测试 pageDeleted\n\n- **功能**：分页查询已逻辑删除的数据。\n- **请求方式**：GET\n- **URL**：`http://localhost:10051/api/post/pageDeleted`\n- **响应示例**：\n\n  ```json\n  {\n    \"data\": {\n      \"total\": 1,\n      \"list\": [\n        {\n          \"title\": \"测试文章\",\n          \"content\": \"这是一篇测试文章。\",\n          \"author\": \"admin\",\n          \"status\": \"archived\",\n          \"id\": \"361177594135064576\"\n        }\n      ]\n    },\n    \"code\": 1,\n    \"msg\": null,\n    \"ok\": true\n  }\n  ```\n\n### 测试 recover\n\n- **功能**：恢复已逻辑删除的数据。\n- **请求方式**：POST\n- **URL**：`http://localhost:10051/api/post/recover`\n- **请求体**：\n\n  ```json\n  {\n    \"id\": \"361177594135064576\"\n  }\n  ```\n\n- **响应示例**：\n\n  ```json\n  {\n    \"data\": null,\n    \"code\": 1,\n    \"msg\": \"恢复成功\",\n    \"ok\": true\n  }\n  ```\n\n### 测试 tableNames\n\n- **功能**：获取数据库中所有表名。\n- **请求方式**：GET\n- **URL**：`http://localhost:10051/api/post/tableNames`\n- **响应示例**：\n\n  ```json\n  {\n    \"data\": [\n      \"system_users\",\n      \"tio_boot_admin_article\"\n      // 其他表名...\n    ],\n    \"code\": 1,\n    \"msg\": null,\n    \"ok\": true\n  }\n  ```\n\n### 测试 fConfig\n\n- **功能**：获取指定表的配置，用于前端展示等。\n- **请求方式**：GET\n- **URL**：`http://localhost:10051/api/post/config?lang=en`\n- **请求参数**：\n  - `lang=en` （可选，用于指定语言）\n- **响应示例**：\n\n  ```json\n  {\n    \"code\": 1,\n    \"data\": {\n      // 配置信息\n    },\n    \"msg\": null,\n    \"ok\": true\n  }\n  ```\n\n### 测试 proTableColumns\n\n- **功能**：获取指定表的字段信息。\n- **请求方式**：GET\n- **URL**：`http://localhost:10051/api/post/columns`\n- **响应示例**：\n\n  ```json\n  {\n    \"code\": 1,\n    \"data\": [\n      {\n        \"title\": \"Id\",\n        \"dataIndex\": \"id\",\n        \"valueType\": \"text\"\n      },\n      {\n        \"title\": \"Title\",\n        \"dataIndex\": \"title\",\n        \"valueType\": \"text\"\n      },\n      {\n        \"title\": \"Content\",\n        \"dataIndex\": \"content\",\n        \"valueType\": \"textarea\"\n      }\n      // 其他字段信息...\n    ],\n    \"ok\": true\n  }\n  ```\n\n## 总结\n\n通过封装 **ApiTableService**，实现了对 **ApiTable** 操作的集中管理，极大地简化了控制器中的代码逻辑，提高了代码的可读性和可维护性。结合 **tio-boot** 框架的特性，进一步提升了开发效率和系统的稳定性。\n\n在实际项目中，开发者可以根据业务需求，扩展 **ApiTableService** 的功能，或者创建更多的控制器来处理不同的数据表操作。同时，合理配置数据库连接池和优化查询条件，可以进一步提升系统的性能和响应速度。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flitongjava%2Fapi-table","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flitongjava%2Fapi-table","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flitongjava%2Fapi-table/lists"}