使用 ApiTable 连接 SQLite

入门示例

创建数据表并插入数据

SQLite 是一种轻量级嵌入式数据库。使用 Navicat Premium 可以轻松创建 SQLite 数据库,数据库文件将保存在本地。

以下是一个创建表并插入数据的示例:

CREATE TABLE "student" (
  "id" integer NOT NULL,
  "name" text NOT NULL,
  "grade" text NOT NULL,
  PRIMARY KEY ("id")
);

INSERT INTO "student" VALUES (1, '沈', '一年级');

整合 SQLite

在项目中整合 SQLite,首先需要添加以下依赖:

<!-- https://central.sonatype.com/artifact/com.litongjava/api-table -->
<dependency>
  <groupId>com.litongjava</groupId>
  <artifactId>api-table</artifactId>
  <version>${api-table.version}</version>
</dependency>

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.1.23</version>
</dependency>

<!-- sqlite-jdbc -->
<dependency>
  <groupId>org.xerial</groupId>
  <artifactId>sqlite-jdbc</artifactId>
  <version>3.7.2</version>
</dependency>

app.properties 配置文件中添加以下配置:

# SQLite 数据库配置
jdbc.driverClass=org.sqlite.JDBC
jdbc.url=jdbc:sqlite:D:/sqlite/student.db
jdbc.user=
jdbc.pswd=
jdbc.showSql=true
jdbc.validationQuery=select 1

配置类的创建

以下是配置 SQLite 数据源和 ActiveRecord 插件的示例代码:

package com.litongjava.address.config;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import javax.sql.DataSource;

import com.alibaba.druid.pool.DruidDataSource;
import com.jfinal.template.Engine;
import com.jfinal.template.source.ClassPathSourceFactory;
import com.litongjava.annotation.AConfiguration;
import com.litongjava.annotation.AInitialization;
import com.litongjava.db.activerecord.ActiveRecordPlugin;
import com.litongjava.db.activerecord.OrderedFieldContainerFactory;
import com.litongjava.db.activerecord.dialect.Sqlite3Dialect;
import com.litongjava.db.hikaricp.DsContainer;
import com.litongjava.tio.boot.server.TioBootServer;
import com.litongjava.tio.utils.environment.EnvUtils;

import lombok.extern.slf4j.Slf4j;

@AConfiguration
@Slf4j
public class DbConfig {

  public DataSource dataSource() {
    String jdbcUrl = EnvUtils.get("jdbc.url");
    String jdbcUser = EnvUtils.get("jdbc.user");
    String jdbcPswd = EnvUtils.get("jdbc.pswd");
    String jdbcValidationQuery = EnvUtils.get("jdbc.validationQuery");

    log.info("jdbcUrl:{}", jdbcUrl);

    // 检查并创建 SQLite 数据库路径
    try {
      if (jdbcUrl != null && jdbcUrl.startsWith("jdbc:sqlite:")) {
        String dbPath = jdbcUrl.substring("jdbc:sqlite:".length());
        Path path = Paths.get(dbPath).getParent();
        if (path != null && !Files.exists(path)) {
          Files.createDirectories(path);
          log.info("已创建 SQLite 数据库目录: {}", path);
        }
      }
    } catch (IOException e) {
      log.error("创建 SQLite 数据库目录失败", e);
      throw new RuntimeException(e);
    }

    // 创建数据源
    DruidDataSource druidDataSource = new DruidDataSource();
    druidDataSource.setUrl(jdbcUrl);
    druidDataSource.setUsername(jdbcUser);
    druidDataSource.setPassword(jdbcPswd);
    druidDataSource.setValidationQuery(jdbcValidationQuery);

    // 保存数据源
    DsContainer.setDataSource(druidDataSource);

    // 关闭服务器时关闭数据源
    TioBootServer.me().addDestroyMethod(druidDataSource::close);
    return druidDataSource;
  }

  @Initialization
  public void activeRecordPlugin() {
    boolean dev = EnvUtils.isDev();
    boolean jdbcShowSql = EnvUtils.getBoolean("jdbc.showSql", false);

    // 创建 ActiveRecord 插件
    ActiveRecordPlugin arp = new ActiveRecordPlugin(dataSource());
    arp.setDialect(new Sqlite3Dialect());
    arp.setContainerFactory(new OrderedFieldContainerFactory());
    arp.setShowSql(jdbcShowSql);

    if (dev) {
      arp.setDevMode(true);
    }

    // 配置模板引擎
    Engine engine = arp.getEngine();
    engine.setSourceFactory(new ClassPathSourceFactory());
    engine.setCompressorOn(' ');
    engine.setCompressorOn('\n');

    // 启动插件
    arp.start();

    // 关闭服务器时关闭插件
    TioBootServer.me().addDestroyMethod(arp::stop);
  }
}

启动类的创建

以下是启动类的示例代码:

import com.litongjava.hotswap.wrapper.tio.boot.TioApplicationWrapper;
import com.litongjava.jfinal.aop.annotation.AComponentScan;

@AComponentScan
public class TioBootSqlLiteApp {

  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    TioApplicationWrapper.run(TioBootSqlLiteApp.class, args);
    long end = System.currentTimeMillis();
    System.out.println((end - start) + "ms");
  }
}

创建 Controller

以下是一个简单的 Controller,用于从数据库中检索数据并返回:

import java.util.List;

import com.litongjava.data.model.DbJsonBean;
import com.litongjava.data.services.DbJsonService;
import com.litongjava.jfinal.aop.annotation.AAutowired;
import com.litongjava.jfinal.plugin.activerecord.Record;
import com.litongjava.annotation.RequestPath;

@RequestPath("/api")
public class TestController {

  @AAutowired
  private DbJsonService dbJsonService;

  @RequestPath("/list")
  public DbJsonBean<List<Record>> list() {
    return dbJsonService.listAll("student");
  }
}

访问测试

启动应用后,访问以下 URL 来测试数据库连接和数据查询功能:

测试代码可在 GitHub 上找到:

自动创建数据库和表

SQLite 会自动创建数据库文件,但不会创建不存在的目录。在上面的 DbConfig 类的 dataSource 方法中,已经包含了创建目录的逻辑。除此之外,我们还需要手动编写创建表的代码。

以下是一个示例代码,用于在数据库中自动创建表:

package com.litongjava.address.config;

import java.net.URL;
import java.util.List;

import com.litongjava.db.activerecord.Db;
import com.litongjava.tio.utils.hutool.FileUtil;
import com.litongjava.tio.utils.hutool.ResourceUtil;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class DbTables {

  public static void init() {
    String userTableName = "tio_boot_admin_system_users";

    boolean created = createTable(userTableName);
    if (created) {
      URL url = ResourceUtil.getResource("sql/tio_boot_admin_system_users_init.sql");
      StringBuilder stringBuilder = FileUtil.readURLAsString(url);
      int update = Db.update(stringBuilder.toString());
      log.info("add user:{},{}", userTableName, update);
    }

  }

  private static boolean createTable(String userTableName) {
    String sql = "SELECT name FROM sqlite_master WHERE type='table' AND name=?";
    List<String> tables = Db.queryListString(sql, userTableName);
    int size = tables.size();
    if (size < 1) {
      URL url = ResourceUtil.getResource("sql/" + userTableName + ".sql");
      StringBuilder stringBuilder = FileUtil.readURLAsString(url);
      int update = Db.update(stringBuilder.toString());
      log.info("created:{},{}", userTableName, update);
      return true;
    }
    return false;
  }
}

src\main\resources\sql\tio_boot_admin_system_users.sql 文件是实际执行的 SQL 文件,用于创建所需的数据库表。

CREATE TABLE tio_boot_admin_system_users (
    id BIGINT NOT NULL,
    username VARCHAR(30) NOT NULL,
    password VARCHAR(100) NOT NULL DEFAULT '',
    nickname VARCHAR(30) NOT NULL,
    signature VARCHAR(200),
    title VARCHAR(50),
    group_name VARCHAR(50),
    tags JSON,
    notify_count INT DEFAULT 0,
    unread_count INT DEFAULT 0,
    country VARCHAR(50),
    access VARCHAR(20),
    geographic JSON,
    address VARCHAR(200),
    remark VARCHAR(500),
    dept_id BIGINT,
    post_ids VARCHAR(255),
    email VARCHAR(50) DEFAULT '',
    phone VARCHAR(11) DEFAULT '',
    sex SMALLINT DEFAULT 0,
    avatar VARCHAR(512) DEFAULT '',
    status SMALLINT NOT NULL DEFAULT 0,
    login_ip VARCHAR(50) DEFAULT '',
    login_date TIMESTAMP WITHOUT TIME ZONE,
    creator VARCHAR(64) DEFAULT '',
    create_time TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updater VARCHAR(64) DEFAULT '',
    update_time TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
    deleted SMALLINT  NOT NULL DEFAULT 0,
    tenant_id BIGINT NOT NULL DEFAULT 0,
    PRIMARY KEY (id),
    UNIQUE (username)
);

src\main\resources\sql\tio_boot_admin_system_users_init.sql

INSERT INTO tio_boot_admin_system_users (
    id, username, password, nickname, signature, title, group_name, tags, notify_count, unread_count, country, access, geographic, address, remark, dept_id, post_ids, email, phone, sex, avatar, status, login_ip, login_date, creator, create_time, updater, update_time, deleted, tenant_id
) VALUES (
    1, 'admin', '8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918', 'admin', 'This is a signature', 'Admin', 'Administrators', '{"tags": [{"key": "tag1", "label": "Tag 1"}, {"key": "tag2", "label": "Tag 2"}]}', 10, 5, 'United States', 'admin', '{"province": {"label": "California", "key": "CA"}, "city": {"label": "San Francisco", "key": "SF"}}', '123 Main St, San Francisco, CA 94122', '管理员', 103, '[1]', 'aoteman@126.com', '15612345678', 1, 'http://127.0.0.1:48080/admin-api/infra/file/4/get/37e56010ecbee472cdd821ac4b608e151e62a74d9633f15d085aee026eedeb60.png', 0, '127.0.0.1', '2023-11-30 09:16:00', 'admin', '2021-01-05 17:03:47', NULL, '2024-03-23 08:49:55', 0, 1
);

在 DbConfig 中执行 初始化方法

DbTables.init();