SQLite在安卓中的应用
在 Android 应用程序中,SQLite 是默认的嵌入式数据库解决方案,Android 系统为开发者提供了相应的 API 来管理 SQLite 数据库。通过使用 SQLiteOpenHelper 类和 SQLiteDatabase 类,开发者可以方便地创建、查询、更新和删除数据库中的数据。
以下是关于如何在 Android 中使用 SQLite 的详细介绍和示例。
一、在 Android 中使用 SQLite 的步骤
1. 创建 SQLiteOpenHelper 类
SQLiteOpenHelper 是一个辅助类,用于管理数据库的创建和版本管理。它提供了两个重要的方法:
onCreate(SQLiteDatabase db):当数据库第一次创建时调用。onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):当数据库需要升级时调用。
示例:创建 SQLiteOpenHelper 子类
public class MyDatabaseHelper extends SQLiteOpenHelper {private static final String DATABASE_NAME = "MyDatabase.db"; // 数据库名称private static final int DATABASE_VERSION = 1; // 数据库版本public MyDatabaseHelper(Context context) {super(context, DATABASE_NAME, null, DATABASE_VERSION);}// 第一次创建数据库时调用@Overridepublic void onCreate(SQLiteDatabase db) {// 创建数据库中的表String CREATE_TABLE = "CREATE TABLE users ("+ "id INTEGER PRIMARY KEY AUTOINCREMENT,"+ "name TEXT NOT NULL,"+ "age INTEGER,"+ "email TEXT);";db.execSQL(CREATE_TABLE);}// 当数据库版本升级时调用@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// 如果表已存在则删除,重新创建db.execSQL("DROP TABLE IF EXISTS users");onCreate(db);}
}
DATABASE_NAME定义了数据库的名称。DATABASE_VERSION是数据库的版本号,每当数据库结构发生变化时,需要升级版本号。onCreate()方法在数据库首次创建时调用,执行 SQL 语句来创建数据库中的表。onUpgrade()方法在数据库需要升级时调用,可以用于处理表结构的变更。
2. 打开数据库
使用 SQLiteOpenHelper 类时,可以通过调用 getWritableDatabase() 或 getReadableDatabase() 方法来打开数据库。前者允许执行写操作,而后者只允许执行读操作。
MyDatabaseHelper dbHelper = new MyDatabaseHelper(context);
SQLiteDatabase db = dbHelper.getWritableDatabase();
3. 插入数据
使用 insert() 方法将数据插入到表中。
// 创建一个 ContentValues 对象,用于存储键值对
ContentValues values = new ContentValues();
values.put("name", "Alice");
values.put("age", 25);
values.put("email", "alice@example.com");// 插入数据
long newRowId = db.insert("users", null, values);
ContentValues类用于保存列名与列值的映射。insert()方法将数据插入到指定的表中,返回插入数据的行 ID。
4. 查询数据
使用 query() 方法从数据库中查询数据。该方法返回一个 Cursor 对象,用于遍历查询结果。
// 定义要查询的列
String[] projection = {"id","name","age","email"
};// 查询数据
Cursor cursor = db.query("users", // 表名projection, // 要返回的列null, // WHERE 子句null, // WHERE 子句的参数null, // GROUP BY 子句null, // HAVING 子句null // 排序方式
);// 遍历查询结果
while (cursor.moveToNext()) {long userId = cursor.getLong(cursor.getColumnIndexOrThrow("id"));String userName = cursor.getString(cursor.getColumnIndexOrThrow("name"));int userAge = cursor.getInt(cursor.getColumnIndexOrThrow("age"));String userEmail = cursor.getString(cursor.getColumnIndexOrThrow("email"));
}// 关闭游标
cursor.close();
projection定义了需要查询的列。Cursor对象用于从查询结果中提取数据,moveToNext()方法用于遍历结果集。
5. 更新数据
使用 update() 方法更新表中的数据。
// 创建 ContentValues 对象
ContentValues values = new ContentValues();
values.put("age", 26);// 更新记录
String selection = "name = ?";
String[] selectionArgs = { "Alice" };int count = db.update("users", // 表名values, // 要更新的值selection, // WHERE 子句selectionArgs // WHERE 子句的参数
);
update()方法根据指定的条件更新表中的记录,返回受影响的行数。
6. 删除数据
使用 delete() 方法删除表中的数据。
// 定义删除条件
String selection = "name = ?";
String[] selectionArgs = { "Alice" };// 删除记录
int deletedRows = db.delete("users", selection, selectionArgs);
delete()方法根据指定的条件删除表中的记录,返回删除的行数。
二、数据库操作的异步处理
在 Android 中,数据库操作通常需要在子线程中进行,以避免在主线程上执行耗时操作,防止阻塞 UI。
可以使用 AsyncTask、HandlerThread 或 Jetpack 提供的 Room 库来简化和管理异步的数据库操作。
使用 Room 作为 SQLite 的抽象层
Room 是 Android Jetpack 提供的一个持久性库,它简化了与 SQLite 的交互,并且支持异步查询。使用 Room 可以避免手动编写大量的 SQL 代码,并提供类型安全的 API。
Room 的基础组件:
- 实体 (Entity):对应数据库中的表。
- DAO (Data Access Object):定义数据操作方法。
- 数据库 (Database):数据库持有者,管理实体和 DAO。
示例:使用 Room 管理数据库
- 定义实体类:
@Entity
public class User {@PrimaryKey(autoGenerate = true)public int id;public String name;public int age;public String email;
}
- 定义 DAO 接口:
@Dao
public interface UserDao {@Insertvoid insertUser(User user);@Query("SELECT * FROM User WHERE id = :id")User getUserById(int id);@Updatevoid updateUser(User user);@Deletevoid deleteUser(User user);
}
- 创建数据库类:
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {public abstract UserDao userDao();
}
- 初始化 Room 数据库:
AppDatabase db = Room.databaseBuilder(getApplicationContext(),AppDatabase.class, "MyDatabase").build();// 在子线程中执行数据库操作
new Thread(() -> {User user = new User();user.name = "Alice";user.age = 25;user.email = "alice@example.com";db.userDao().insertUser(user);
}).start();
三、SQLite 数据库备份和恢复
由于 SQLite 数据存储在一个单一的文件中,因此备份和恢复操作非常简单。可以直接复制数据库文件来备份或恢复数据。
备份数据库文件:
File dbFile = context.getDatabasePath("MyDatabase.db");
File backupFile = new File(Environment.getExternalStorageDirectory(), "MyDatabase_backup.db");try (FileChannel src = new FileInputStream(dbFile).getChannel();FileChannel dst = new FileOutputStream(backupFile).getChannel()) {dst.transferFrom(src, 0, src.size());
} catch (IOException e) {e.printStackTrace();
}
恢复数据库文件:
File dbFile = context.getDatabasePath("MyDatabase.db");
File backupFile = new File(Environment.getExternalStorageDirectory(), "MyDatabase_backup.db");try (FileChannel src = new FileInputStream(backupFile).getChannel();FileChannel dst = new FileOutputStream(dbFile).getChannel()) {dst.transferFrom(src, 0, src.size());
} catch (IOException e) {e.printStackTrace();
}
四、SQLite 数据库的性能优化
-
使用索引:为经常查询的列创建索引可以显著提升查询速度。
CREATE INDEX idx_user_name ON users(name); -
事务处理:将多个操作放在一个事务中执行,可以减少磁盘 I/O,从而提高性能。
BEGIN TRANSACTION; -- 执行多条 SQL 语句 COMMIT; -
按需加载数据:在查询大量数据时,使用分页查询减少内存消耗。
SELECT * FROM users LIMIT 10 OFFSET 20;
通过上述步骤,开发者可以轻松在 Android 中集成并使用 SQLite 数据库。为了进一步深入理解,接下来将继续介绍 SQLite 在 Android 中的性能优化、常见的最佳实践,以及在不同场景下的高级用法。
五、SQLite 在 Android 中的性能优化
SQLite 数据库在 Android 应用中处理小规模数据时表现非常优异,但当数据量增大时,可能会面临性能问题。以下是几种常见的性能优化方法:
1. 使用事务
将多条 SQL 操作放在一个事务中可以显著提升数据库操作的效率。SQLite 的每一条独立的插入或更新操作都会触发一次磁盘写操作,增加了 I/O 的开销。如果将多条插入或更新操作包裹在同一个事务中,则只会有一次磁盘写入,减少了 I/O 操作,极大提高了性能。
示例:使用事务插入多条记录
db.beginTransaction();
try {for (User user : userList) {ContentValues values = new ContentValues();values.put("name", user.getName());values.put("age", user.getAge());values.put("email", user.getEmail());db.insert("users", null, values);}db.setTransactionSuccessful(); // 标记事务成功
} finally {db.endTransaction(); // 结束事务
}
db.beginTransaction()开启事务。db.setTransactionSuccessful()在事务成功时调用。db.endTransaction()结束事务。
2. 使用索引 (Indexing)
为常用查询的列创建索引,可以加速查询速度。索引本质上是表中特定列的排序结构,它减少了查询时的扫描行数。
创建索引的示例:
CREATE INDEX idx_user_name ON users(name);
注意,虽然索引可以加快查询速度,但也会增加插入和更新操作的开销,因此应根据需要平衡索引的使用。
3. 减少数据查询
在查询数据时,避免使用 SELECT * 来检索所有列,尽量只查询需要的列,减少不必要的数据传输。
示例:只查询需要的列
String[] projection = {"id","name"
};
Cursor cursor = db.query("users",projection,null,null,null,null,null
);
4. 使用批量操作
在处理大批量数据操作时,使用批量插入、更新或删除可以提高操作效率。批量操作可以通过事务和 SQLiteStatement 提高性能。
批量插入示例:
SQLiteStatement stmt = db.compileStatement("INSERT INTO users (name, age, email) VALUES (?, ?, ?)");db.beginTransaction();
try {for (User user : userList) {stmt.bindString(1, user.getName());stmt.bindLong(2, user.getAge());stmt.bindString(3, user.getEmail());stmt.execute();stmt.clearBindings();}db.setTransactionSuccessful();
} finally {db.endTransaction();
}
5. 使用 PRAGMA 进行性能调优
SQLite 提供了许多 PRAGMA 命令,允许开发者动态配置数据库的行为,从而提升性能。例如:
PRAGMA synchronous = OFF;:关闭同步写入,提升写入速度(在数据一致性不是首要关注时使用)。PRAGMA journal_mode = WAL;:将数据库设置为“写入时日志”模式,这样可以在高并发读写的场景下提升性能。
示例:设置 WAL 模式
PRAGMA journal_mode = WAL;
在 WAL 模式下,写操作不会直接覆盖原数据,而是记录在日志中,并在空闲时间将日志内容合并回主数据库文件,从而提高并发读写的性能。
六、SQLite 的最佳实践
1. 善用 ContentValues 和 Cursor
- 使用
ContentValues来存储插入或更新的数据,不仅简化了代码,还提高了可读性。 - 使用
Cursor遍历查询结果时,始终在使用后关闭Cursor,防止内存泄漏。
关闭 Cursor 示例:
Cursor cursor = db.query("users", null, null, null, null, null, null);
try {while (cursor.moveToNext()) {// 获取数据}
} finally {cursor.close(); // 确保 cursor 关闭
}
2. 使用 Room 框架
在复杂的 Android 应用程序中,直接使用 SQLite 可能会导致 SQL 语句冗长、难以维护。为了简化与 SQLite 的交互,推荐使用 Room 框架,它提供了类型安全的 API,并能与 LiveData 和 RxJava 轻松集成,实现异步查询操作。
3. 避免在主线程进行数据库操作
数据库操作可能会耗时较长,尤其是在处理大数据集或网络存储时。为了避免 UI 卡顿,务必在工作线程中执行数据库操作。可以使用 AsyncTask、ExecutorService 或 Room 提供的异步操作方法。
示例:使用 ExecutorService 进行异步操作
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {// 在后台线程中执行数据库操作db.userDao().insertUser(user);
});
4. 确保数据库版本管理
当数据库的结构发生变化时,需要通过增加数据库的版本号并在 onUpgrade() 中进行适当的迁移操作,以确保数据的完整性。
版本升级示例:
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {if (oldVersion < 2) {db.execSQL("ALTER TABLE users ADD COLUMN phone TEXT");}
}
通过这种方式,可以安全地向数据库表中添加新字段,而不会破坏现有数据。
七、SQLite 高级用法
1. 数据库加密
Android 系统默认的 SQLite 数据库是不加密的。如果需要对敏感数据进行加密,可以使用 SQLCipher 这样的第三方库。SQLCipher 是对 SQLite 的增强版,提供了对数据库文件的透明加密支持。
使用 SQLCipher 加密数据库:
- 添加依赖:
implementation 'net.zetetic:android-database-sqlcipher:4.5.0'
- 创建或打开加密数据库:
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(databaseFile, "your-password", null);
通过加密,数据在数据库文件中存储时将是加密的,即使文件被拷贝,未经授权的用户也无法直接查看数据。
2. 数据库迁移
当应用程序的数据库架构需要更新时,必须处理好数据迁移。Room 框架提供了方便的迁移机制,可以帮助开发者在数据库版本升级时保持数据的完整性。
Room 迁移示例:
Migration MIGRATION_1_2 = new Migration(1, 2) {@Overridepublic void migrate(@NonNull SupportSQLiteDatabase database) {database.execSQL("ALTER TABLE users ADD COLUMN phone TEXT");}
};Room.databaseBuilder(context, AppDatabase.class, "MyDatabase").addMigrations(MIGRATION_1_2).build();
通过 Room 的迁移功能,数据库的版本升级变得更加安全和可控。
3. 数据库备份与恢复
SQLite 的备份和恢复操作可以通过文件操作来实现。开发者可以直接复制 SQLite 数据库文件以创建备份,或者通过将文件移动到安全的存储位置来进行恢复。
示例:备份数据库文件到外部存储
File dbFile = context.getDatabasePath("MyDatabase.db");
File backupFile = new File(Environment.getExternalStorageDirectory(), "MyDatabase_backup.db");try (FileChannel src = new FileInputStream(dbFile).getChannel();FileChannel dst = new FileOutputStream(backupFile).getChannel()) {dst.transferFrom(src, 0, src.size());
} catch (IOException e) {e.printStackTrace();
}
示例:从备份文件恢复数据库
File dbFile = context.getDatabasePath("MyDatabase.db");
File backupFile = new File(Environment.getExternalStorageDirectory(), "MyDatabase_backup.db");try (FileChannel src = new FileInputStream(backupFile).getChannel();FileChannel dst = new FileOutputStream(dbFile).getChannel()) {dst.transferFrom(src, 0, src.size());
} catch (IOException e) {e.printStackTrace();
}
总结
SQLite 是一个轻量、可靠、简单易用的数据库解决方案,特别适合嵌入式系统和移动应用中的数据存储需求。通过 Android 提供的 API,开发者可以轻松地实现数据持久化功能。在实际开发中
相关文章:
SQLite在安卓中的应用
在 Android 应用程序中,SQLite 是默认的嵌入式数据库解决方案,Android 系统为开发者提供了相应的 API 来管理 SQLite 数据库。通过使用 SQLiteOpenHelper 类和 SQLiteDatabase 类,开发者可以方便地创建、查询、更新和删除数据库中的数据。 以…...
Python数据库操作
前面的章节中学习了使用 Python 读写文件的方法,大家可以用文件方式来存放数据,不过使用文件方式时不容易管理,同时还容易丢失,会带来许多问题。目前主流的方法都是采用数据库软件,通过数据库软件来组织和存放数据&…...
交叉熵损失函数为代表的两层神经网络的反向传播量化求导计算公式
反向传播(back propagation,BP)算法也称误差逆传播,是神经网络训练的核心算法。我们通常说的 BP 神经网络是指应用反向传播算法进行训练的神经网络模型。反向传播算法的工作机制究竟是怎样的呢?我们以一个两层…...
数据结构——八大排序(上)
数据结构中的八大排序算法是计算机科学领域经典的排序方法,它们各自具有不同的特点和适用场景。以下是这八大排序算法的详细介绍: 一、插入排序(Insertion Sort) 核心思想:将数组中的所有元素依次跟前面已经排好的元…...
vxe-table 导入导出功能全解析
一、vxe-table 导入导出功能概述 vxe-table 的导入导出功能在数据处理中具有至关重要的作用。在现代数据管理和处理的场景中,高效地导入和导出数据是提高工作效率的关键。 对于导入功能而言,它允许用户将外部的表格数据,如 Excel 文件&…...
常用STL的操作以及特点
C 标准模板库(STL)提供了很多常用的数据结构和算法,极大简化了开发工作。STL 包括容器(如 vector、list、map 等)、算法(如排序、查找等)以及迭代器。以下是一些常用 STL 容器的操作以及它们的特…...
025 elasticsearch索引管理-Java原生客户端
文章目录 pom.xml1创建索引2.创建索引并设置settings信息3.创建索引并设置mapping信息4.删除索引库5.给未设置mapping的索引设置mapping elasticsearch版本7.10.2,要求java客户端与之相匹配,推荐Springboot版本是2.3以上版本 依赖配置使用的是JUnit 5&am…...
Gin框架操作指南10:服务器与高级功能
官方文档地址(中文):https://gin-gonic.com/zh-cn/docs/ 注:本教程采用工作区机制,所以一个项目下载了Gin框架,其余项目就无需重复下载,想了解的读者可阅读第一节:Gin操作指南&#…...
AIGC技术的学习 系列一
文章目录 前言一、AIGC技术演进1.1 图像视频生成1.2. 文本生成1.3. 多模态生成1.4. 小结二、CAD&CAE软件介绍2.1. CAD软件2.2. CAE软件2.3. 小结三、AIGC技术与CAD&CAE软件的集成案例3.1. 土建设计领域3.2. 机械设计领域四、结语五、参考文献总结前言 在全球智能制造的…...
Milvus×Dify半小时轻松构建RAG系统
最近,检索增强生成(RAG)技术在AI界引起了广泛关注。作为一种将知识库与生成模型结合的新型架构,RAG大大提升了AI应用的实际表现。而在构建RAG系统时,Milvus作为业界领先的开源向量数据库,扮演着关键角色。本…...
wireshark 解密浏览器https数据包
一、导出浏览器证书有两种方法 1、在浏览器快捷方式追加启动参数: --ssl-key-log-file"d:\log\2.log" C:\Users\Administrator\AppData\Local\Google\Chrome\Application\chrome.exe --ssl-key-log-file"d:\log\2.log" 2、环境变量中新建用…...
【HTML】构建网页的基石
我的主页:2的n次方_ HTML 是一种超文本标记语言,不仅有文本,还能包含图片,音频等 1. HTML 的文件基本结构 html 标签是整个 html 文件的最顶层标签,head 标签中写页面的属性,body 标签是页面中显示的…...
rust不允许在全局区定义普通变量!
文章目录 C 中的全局变量Rust 中的全局变量设计哲学的体现 在 C 和 Rust 中,全局变量的处理方式体现了这两种语言设计哲学上的一些根本性差异: C 中的全局变量 C 允许在全局作用域中定义变量。这些变量在程序的整个生命周期内都存在,从程序开…...
量化投资中的数据驱动决策:大数据如何改变金融市场
随着科技的进步,金融行业迎来了前所未有的变革,量化投资作为其中的代表,逐渐成为投资市场的主流。量化投资是基于数学模型、数据分析以及算法策略的投资方式,与传统依赖经验和直觉的投资方法相比,它的核心优势在于能够…...
MySQL 设计数据表
一个数据表主要包含信息有 : 表名、主键、字段、数据类型、索引,本节主要介绍表的命名规范、字段命名、字段的数据类型选择。 新建的表都是新建在 “item_name” 数据库中的,新建 “item_name” 数据库命令如下 : CREATE DATABASE item_name;新建数据库…...
【大数据技术基础 | 实验一】配置SSH免密登录
文章目录 一、实验目的二、实验要求三、实验原理(一)大数据实验一体机(二)SSH免密认证 四、实验环境五、实验内容和步骤(一)搭建集群服务器(二)添加域名映射(三ÿ…...
地级市碳排放效率测算2006-2021年
为了测算碳排放效率,研究者们采用了多种方法,其中超效率SBM(Slack-Based Measure)和超效率CCR(Charnes, Cooper and Rhodes)模型是常用的两种方法。这些模型可以有效地评估决策单元的相对有效性,…...
周易解读:四象
四 象 在前面呢,我是讲完了太极与两仪的知识。这一节,我们来讲解四象的内容。 关于四象的知识,它在正式的周易的经文里面,它并没有多少用处。但是呢,在基础知识的学习里面,四象的知识,大家是…...
Java设计模式梳理:行为型模式(策略,观察者等)
行为型模式 行为型模式关注的是各个类之间的相互作用,将职责划分清楚,使得我们的代码更加地清晰。 策略模式 策略模式太常用了,所以把它放到最前面进行介绍。它比较简单,我就不废话,直接用代码说事吧。 下面设计的…...
【MySQL】入门篇—基本数据类型:使用LIMIT限制结果集
为了提高查询效率和用户体验,MySQL提供了LIMIT子句,用于限制查询结果的行数。LIMIT不仅可以提高性能,还可以帮助用户快速获取所需的数据,尤其在分页显示数据时非常有用。 应用场景: 分页显示:在网页应用中…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
