JSON-Server
一个在前端本地运行,可以存储json数据的server。前端开发可以模拟服务端接口数据,在本地搭建一个JSON服务,自己产生测试数据。
- 使用npm全局安装json-server :npm install -g json-server
- 可以通过查看版本号,来测试是否安装成功:json-server -v
- 创建json数据——db.json
在任意一个文件夹下(此处假设创建一个server文件夹),进入到该文件夹里面,执行代码 json-server --watch db.json - 此时文件夹下多出一个db.json文件
- 启动
json-server --watch db.json
,访问 http://localhost:3000/ - 分别点击/posts /comments /profile /db链接,我们可以看到访问不同URL返回不同的json数据。其中 /db返回的是整个json文件的数据。
- 修改端口号
默认3000--port 3004
或者在db.json同级文件夹新建一个package.json,在script配置添加运行命令:
{
"scripts": {
"mock": "json-server db.json --port 3004"
}
}
//运行时, 直接在当前文件夹下执行 npm run mock
- 操作数据 | 增删改查
json-server 支持 restful 风格的api,可以通过不同的请求方式,对数据进行增删改查等不同的操作。
先修改db.json文件:
{
"users": [
{
"id": 1,
"name": "liaoyi",
"phone": "13246566776",
"age": 22,
"classId": "1002"
},
{
"name": "林更新",
"age": "44",
"id": 4,
"classId": "1003"
},
{
"name": "李响",
"phone": "18779756778",
"age": "26",
"id": 5,
"classId": "1003"
},
{
"name": "陈温柔",
"phone": "18779756000",
"age": "22",
"id": 6,
"sex": "0",
"classId": "1004"
},
{
"name": "夏琪",
"phone": "13246579999",
"age": "22",
"id": 7,
"classId": "1004"
}
],
"class": [
{
"id": "1",
"title": "前端",
"staff": [
"1002",
"1004"
]
},
{
"id": "2",
"title": "后端",
"staff": [
"1003"
]
}
],
"fruits": [
{
"id": 1,
"name": "苹果",
"price": 1.28
},
{
"id": 2,
"name": "橘子",
"price": 3.88
},
{
"id": 3,
"name": "宁夏西瓜",
"price": 1.98
},
{
"id": 4,
"name": "麒麟西瓜",
"price": 3.98
},
{
"id": 5,
"name": "红蛇果",
"price": 2.5
},
{
"id": 6,
"name": "黑皮西瓜",
"price": 0.98
},
{
"id": 7,
"name": "红心火龙果",
"price": 2.69
},
{
"id": 8,
"name": "国产火龙果",
"price": 1.69
},
{
"id": 9,
"name": "海南荔枝",
"price": 9.9
},
{
"id": 10,
"name": "陕西冬枣",
"price": 5.39
},
{
"id": 11,
"name": "软籽石榴",
"price": 2.39
},
{
"id": 12,
"name": "蜜橘",
"price": 1.99
},
{
"id": 13,
"name": "海南香蕉",
"price": 1.45
}
],
"person": [
{
"name": {
"firstname": "liao",
"lastname": "yi"
},
"pwd": "qwerst54"
},
{
"name": {
"firstname": "wang",
"lastname": "wu"
},
"pwd": "adasff11"
}
]
}
- get 获取数据
浏览器可以直接访问GET请求,可以直接在浏览器访问就能看到返回的json数据。
获取所有用户数据(对象数组): http://localhost:3004/users
获取所有水果数据:http://localhost:3004/fruits
获取数据
根据 id 获取 users 数据:http://localhost:3004/users/1
//get请求的query参数
http://localhost:3004/users?id=1
//传入不同的条件
// 查找名字为 'liaoyi' 的用户
http://localhost:3004/users?name=liaoyi
//多个条件 用&符号连接:
http://localhost:3004/fruits?name=橘子&price=3.88
//甚至还可以使用对象取属性值 obj.key 的方式
http://localhost:3004/person?name.firstname=liao
//分页采用 _page 来设置页码,
// _limit 来控制每页显示条数。
//如果没有指定 _limit ,默认每页显示10条。
http://localhost:3004/fruits?_page=1&_limit=5
http://localhost:3004/fruits?_page=1&_limit=10
http://localhost:3004/fruits?_page=2&_limit=5
//排序采用 _sort 来指定要排序的字段,
// _order 来指定排序是正排序还是逆排序(asc | desc ,默认是asc)。
http://localhost:3004/fruits?_sort=price
http://localhost:3004/fruits?_sort=price&_order=desc
//获取局部数据
//_start 来指定开始位置, _end 来指定结束位置、
//或者_limit指定从开始位置起往后取几个数据。类似Array.slice() 方法
# 使用 _end
http://localhost:3004/fruits?_start=2&_end=4
# 使用 _limit
http://localhost:3004/fruits?_start=2&_limit=4
//获取符合某个范围的数据
1. 使用 _gte 和 _lte 来设置一个取值范围 :
2. 使用 _ne 来获取不包含某个值的数据
3. 采用 _like 来设置匹配某个字符串(或正则表达式)
http://localhost:3004/fruits?id_gte=4&id_lte=6
http://localhost:3004/fruits?id_ne=1&id_ne=10
http://localhost:3004/fruits?name_like=果
//搜索功能 采用 q 来设置搜索内容:
http://localhost:3004/fruits?q=瓜
- 除get请求外,其他请求方式需要我们通过 api 调试工具或者代码的方式来使用。如apifox
<template>
<el-button @click="add"> 发送请求 </el-button>
</template>
<script setup>
import axios from 'axios'
const url = 'http://localhost:3004/users'
const add = async () => {
const data = {
name: '林更新',
phone: '18779756000',
age: '22'
}
const { data: res } = await axios({ method: 'post', url, data })
console.log('res', res)
}
</script>
<template>
<el-button @click="deleteUser"> 删除用户 </el-button>
</template>
<script setup>
import axios from 'axios'
const userId = 3
const url = `http://localhost:3004/users/${userId}`
const deleteUser = async () => {
const res = await axios({ method: 'delete', url })
console.log('res', res)
}
</script>
PUT方法会更新整个资源对象,前端没有给出的字段,会自动清空。但是使用put修改后会有一个问题,只会保留提交的字段,没有提交的字段在json中将会被删除
patch 修改数据 :只修改请求的字段,没有请求的字段将会被保留。
<template>
<el-button @click="reviseUser"> put 修改用户 </el-button>
</template>
<script setup>
import axios from 'axios'
const userId = 4
const url = `http://localhost:3004/users/${userId}`
const reviseUser = async () => {
const data = {
"name": "林更新",
"age": "44"
}
const res = await axios({ method: 'put', url, data })
console.log('res', res)
}
</script>
<template>
<el-button @click="reviseUser"> patch修改用户 </el-button>
</template>
<script setup>
import axios from 'axios'
const userId = 8
const url = `http://localhost:3004/users/${userId}`
const reviseUser = async () => {
const data = {
name: "陈温柔",
age: "22",
sex: "0"
}
const res = await axios({ method: 'patch', url, data })
console.log('res', res)
}
</script>
- 多表查询 | 关联检索
- 向上关联
通过 _expand 方式检索关联父级数据,多对一关系,所以条件是单数。
这里的 _expand=class 匹配即和 users 对象中的 classId做关联,但是已经存在classId字段则写出 class, 比如检索的是 repaId 写成 repa - 通过 _embed 方式检索关联子级数据
注意: 这里_embed 需要和子表名 (要关联的子集属性名) 匹配。一对多关系,所以匹配条件是负数。
//向上关联父级数据
//class 是一个别名
http://localhost:3004/users?_expand=class
//res:
[
{
"id": 1,
"name": "liaoyi",
"phone": "13246566776",
"age": 22,
"classId": "1",
"class": {
"id": "1",
"title": "前端",
"staff": [
"7",
"6",
"1"
]
}
},
{
"name": "林更新",
"age": "44",
"id": 4,
"classId": "2",
"class": {
"id": "2",
"title": "后端",
"staff": [
"4",
"5"
]
}
},
{
"name": "李响",
"phone": "18779756778",
"age": "26",
"id": 5,
"classId": "2",
"class": {
"id": "2",
"title": "后端",
"staff": [
"4",
"5"
]
}
},
{
"name": "陈温柔",
"phone": "18779756000",
"age": "22",
"id": 6,
"sex": "0",
"classId": "1",
"class": {
"id": "1",
"title": "前端",
"staff": [
"7",
"6",
"1"
]
}
},
{
"name": "夏琪",
"phone": "13246579999",
"age": "22",
"id": 7,
"classId": "1",
"class": {
"id": "1",
"title": "前端",
"staff": [
"7",
"6",
"1"
]
}
}
]
//向下关联子级数据
http://localhost:3004/classes?_embed=users
//res:
[
{
"id": "1",
"title": "前端",
"staffIds": [
"1001",
"1004",
"1005"
],
"users": [
{
"id": "1001",
"name": "liaoyi",
"phone": "13246566776",
"age": 22,
"classId": "1"
},
{
"name": "陈温柔",
"phone": "18779756000",
"age": "22",
"id": "1004",
"sex": "0",
"classId": "1"
},
{
"name": "夏琪",
"phone": "13246579999",
"age": "22",
"id": "1005",
"classId": "1"
}
]
},
{
"id": "2",
"title": "后端",
"staffIds": [
"1002",
"1003"
],
"users": [
{
"name": "林更新",
"age": "44",
"id": "1002",
"classId": "2"
},
{
"name": "李响",
"phone": "18779756778",
"age": "26",
"id": "1003",
"classId": "2"
}
]
}
]
- 静态部署
新增配置文件 config.json 并写入
{
"port": "3000", // 设置端口号
"watch": true, // 是否开启监听
"static": "./public/", // 静态资源目录
"read-only": false, // 是否只读
"no-cors": true, // 是否支持跨域
"no-gzip": false // 是否开启压缩
}
//启动命令
json-server --watch data.json config.json
//或者放入package.json+npm run mock
{
"scripts": {
"mock": "json-server --watch data.json config.json"
}
}
mock.js
- Mock.js + json-server 模拟数据
- 创建一个文件夹名为 mock_json
- 进入文件夹后初始化package.json 文件
- 下载依赖
mkdir mock_json
cd mock_json
npm init
npm install json-server mockjs
- 添加启动脚本
{
"name": "mock_json",
"scripts": {
"dev": "json-server --watch db.js --port 3000"
},
"dependencies": {
"json-server": "^0.17.4",
"mockjs": "^1.1.0"
}
}
- 新建 db.js 文件
const Mock = require('mockjs')
const data = Mock.mock({
'users|10-20': [{
'id|+1': '1',
'name': '@name',
'sex|1': ['男', '女'],
'age|18-60': 1,
'address': '@county(true)',
'phone': /^1[34578]\d{9}$/,
'email': '@email',
'birthday': '@date',
'avatar': '@image(200x200, #50B347, #FFF, #78C3FC)',
'desc': '@cparagraph(1, 3)'
}],
'products|122000': [{
'id|+1': 1,
'name': '@word(3,5)',
'price': '@integer(100,999)',
'quantity': '@integer(1,50)',
'brief': '@cparagraph(1, 3)'
}],
})
// 想要用 json-server 识别mockjs的模拟数据内容,需要使用 module.exports 进行模块的对外暴露,并且暴露的类型必须是函数
module.exports = () => data
/* 上面👆 products 有十二万数据,不能直接打开浏览器访问http://localhost:3000/products,浏览器会奔溃的
需要使用查询参分页查询
如: http://localhost:3000/products?_page=1&_limit=10 */
- 启动项目
npm run dev
注意⚠️:
- 想要用 json-server 识别mockjs的模拟数据内容,需要使用 module.exports 进行模块的对外暴露,并且暴露的类型必须是函数。
- 上面 products 我们模拟了十二万条数据,启动时会有点慢,并且不能直接使用浏览器访问http://localhost:3000/products,浏览器会奔溃的。需要使用查询参分页查询, 如:http://localhost:3000/products?_page=1&_limit=10