Python 解析JSON实现主机管理

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它以易于阅读和编写的文本形式表示数据。JSON 是一种独立于编程语言的数据格式,因此在不同的编程语言中都有对应的解析器和生成器。JSON 格式的设计目标是易于理解、支持复杂数据结构和具有良好的可扩展性。

JSON 数据是以键值对的形式存在的,而且易于阅读和编写。以下是一个简单的 JSON 示例:

{"name": "John Doe","age": 30,"city": "New York","isStudent": false,"grades": [95, 88, 75, 92],"address": {"street": "123 Main St","zipCode": "10001"}
}

在这个例子中,JSON 对象包含了一些属性,包括字符串、数字、布尔值、数组和嵌套的对象。

  • "name": "John Doe":字符串键值对。
  • "age": 30:数字键值对。
  • "city": "New York":字符串键值对。
  • "isStudent": false:布尔键值对。
  • "grades": [95, 88, 75, 92]:数组键值对。
  • "address": {...}:嵌套对象。

在实际应用中,JSON 数据通常用于前后端之间的数据交换,或者配置文件的存储。各种编程语言都提供了处理 JSON数据的库或模块。

很早之前大概是两年前,当时为了实现批量管理SSH账号密码并实现自动巡检功能,写过一个简单的命令行工具,通过使用JSON实现对特定主机账号密码与组的管理,如下代码,通过定义AdminDataBase()类,传如数据库文件名database.json实现对特定JSON文件的增删改查功能,在编写该案例后我对JSON的使用变得更加深刻了。

# -*- coding: utf-8 -*-
import os,jsonclass AdminDataBase(object):def __init__(self, database_path):self.database_path = database_path# 判断数据库文件是否存在,不存则则创建一个.def InitDatabase(self):if os.path.exists(self.database_path) != None :init_database = \{"HostList": [["1000", "127.0.0.1", "username", "password", "22"]],"HostGroup": [{"DefaultGroup": ["1000"]}, ],}with open(self.database_path, "w", encoding="utf-8") as fp:fp.write(json.dumps(init_database))print("[+] {} 结构已被初始化.".format(self.database_path))# table 接收一个列表名,根据列表名输出列表中的数据def ShowHostList(self):with open(self.database_path, "r", encoding="utf-8") as Read_Pointer:load_json = json.loads(Read_Pointer.read())base = load_json.get("HostList")print("-" * 80)print("UUID \t 主机地址 \t\t\t 登录用户 \t\t 登录密码 \t 端口")print("-" * 80)for each in range(0, len(base)):print("{0:4} \t {1:15} \t {2:10} \t {3:10} \t {4:10}".format(base[each][0], base[each][1], base[each][2], base[each][3], base[each][4]))print()# 在原来的基础上添加一台新的主机,添加到HostList表中def AddHost(self, uuid, address, username, password, port):with open(self.database_path, "r", encoding="utf-8") as Read_Pointer:# 读取 database.json 中的数据到内存中load_json = json.loads(Read_Pointer.read())# 先读入内存,修改后全部替换进去host_list = load_json.get("HostList")# 获取到最后一次循环的元素列表for each in range(len(host_list) - 1, len(host_list)):# 判断如果UUID不重复则添加,否则跳过添加if (host_list[each][0] != uuid):host_list.append([uuid, address, username, password, port])load_json["HostList"] = host_list# 最后再次将改好的数据,回写到文件保存with open(self.database_path, "w", encoding="utf-8") as Write_Pointer:dump_json = json.dumps(load_json)Write_Pointer.write(dump_json)print("[+] UUID {} 添加成功.".format(uuid))else:print("[-] UUID {} 列表中存在,添加失败.".format(uuid))return 0# 根据传入UUID号修改特定主机数据def ModifyHost(self,uuid,modify_address,modify_username,modify_password,modify_port):with open(self.database_path, "r", encoding="utf-8") as Read_Pointer:# 读取 database.json 中的数据到内存中load_json = json.loads(Read_Pointer.read())host_list = load_json.get("HostList")# 根据uuid寻找一维数组的下标位置index = -1for index, value in enumerate(host_list):if value[0] == uuid:print("[*] 已找到UUID {} 所在下标为 {}".format(uuid,index))breakelse:index = -1# 判断是否找到了,找到了则修改if index != -1:# 修改指定下标数值,并将修改后的数据放入原始JSON文件中host_list[index] = [uuid,modify_address,modify_username,modify_password,modify_port]load_json["HostList"] = host_list# 最后再次将改好的数据,回写到文件保存with open(self.database_path, "w", encoding="utf-8") as Write_Pointer:dump_json = json.dumps(load_json)Write_Pointer.write(dump_json)print("[+] UUID {} 修改完成.".format(uuid))return 0else:print("[-] UUID {} 不存在.".format(uuid))return 0# 根据传入的UUID号删除主机数据,先删除所对的组中的数据,然后在删除主机数据def DeleteHost(self,uuid):with open(self.database_path, "r", encoding="utf-8") as Read_Pointer:load_json = json.loads(Read_Pointer.read())host_group = load_json.get("HostGroup")# 首先在HostGroup中寻找并弹出相应UUIDfor each in range(0,len(host_group)):try:# 循环每个字典for k,v in host_group[each].items():# 判断UUID是否存在于每个字典中if v.count(uuid) != 0:# 移除并放入原始JSON中v.remove(uuid)load_json["HostGroup"] = v# 最后再次将改好的数据,回写到文件保存with open(self.database_path, "w", encoding="utf-8") as Write_Pointer:dump_json = json.dumps(load_json)Write_Pointer.write(dump_json)#print("[+] UUID {} 修改完成.".format(uuid))else:#print("[-] 当前组 {} 不能存在: {}".format(k,uuid))breakexcept Exception:print("[-] 当前组不能存在: {}".format(uuid))return 0# ----------------------------------------------# 其次寻找HostList中的数据并弹出host_list = load_json.get("HostList")try:# 根据uuid寻找一维数组的下标位置index = -1for index, value in enumerate(host_list):if value[0] == uuid:#print("[*] 已找到UUID {} 所在下标为 {}".format(uuid,index))breakelse:index = -1# 如果找到了,则直接根据下标弹出数据if index != -1:host_list.pop(index)load_json["HostList"] = host_list# 最后再次将改好的数据,回写到文件保存with open(self.database_path, "w", encoding="utf-8") as Write_Pointer:dump_json = json.dumps(load_json)Write_Pointer.write(dump_json)print("[+] UUID {} 主机: {} 已被移除.".format(uuid,host_list[index][1]))return 0except Exception:return 0# 向数据库中的HostGroup字段中添加一个主机组def AddHostGroup(self,add_group_name):with open(self.database_path, "r", encoding="utf-8") as Read_Pointer:load_json = json.loads( Read_Pointer.read() )group_obj = load_json.get("HostGroup")# 循环所有字典中的组for each in range(0, len(group_obj)):list_name = str(list(group_obj[each].keys())[0])# print("组节点: {}".format(list_name))# 循环判断表中是否存在指定的组名称if (list_name == add_group_name):print("[-] {} 存在于组中,无法继续添加.".format(list_name))return 0# 读取原始JSON文件,并构建回写参数tmp = {}tmp[add_group_name] = ["1000"]group_obj.append(tmp)# 回写添加主机组with open(self.database_path, "w", encoding="utf-8") as Write_Pointer:dump_json = json.dumps(load_json)Write_Pointer.write(dump_json)print("[+] 主机组 {} 已添加".format(add_group_name))# 在主机组中删除一个主机组def DeleteHostGroup(self,delete_group_name):with open(self.database_path, "r", encoding="utf-8") as Read_Pointer:load_json = json.loads( Read_Pointer.read() )group_obj = load_json.get("HostGroup")# 循环所有字典中的组for each in range(0, len(group_obj)):list_name = str(list(group_obj[each].keys())[0])# 循环判断表中是否存在指定的组名称if (list_name == delete_group_name):# 如果存在于组中,那我们就把他的each弹出列表group_obj.pop(each)# 将弹出后的列表再次写回JSON序列中with open(self.database_path, "w", encoding="utf-8") as Write_Pointer:dump_json = json.dumps(load_json)Write_Pointer.write(dump_json)print("[-] 主机组 {} 已移除.".format(delete_group_name))return 0print("[-] 主机组 {} 不存在.".format(delete_group_name))return 0# 向指定主机组中添加一个主机UUIDdef AddHostGroupOnUUID(self,group_name, uuid):with open(self.database_path, "r", encoding="utf-8") as Read_Pointer:load_json = json.loads( Read_Pointer.read() )group_obj = load_json.get("HostGroup")# 循环所有字典中的所有组for each in range(0, len(group_obj)):list_name = str(list(group_obj[each].keys())[0])# 如果找到了需要添加的组if (list_name == group_name):tmp = group_obj[each]# 获取到原始列表中的数据val = list(tmp.values())[0]# 判断输入的UUID号,是否在val列表中,不在则添加if str(uuid) not in val:val.append(str(uuid))# 将原始数据赋值到新的表中group_obj[each][list_name] = valelse:print("[-] UUID {} 已存在于 {} 主机组,添加失败.".format(uuid,group_name))return 0with open(self.database_path, "w", encoding="utf-8") as Write_Pointer:dump_json = json.dumps(load_json)Write_Pointer.write(dump_json)print("[+] 向主机组 {} 增加UUID {} 完成".format(group_name, uuid))return 0# 从指定主机组中删除一个指定的UUID号def DeleteHostGroupOnUUID(self,group_name, uuid):with open(self.database_path, "r", encoding="utf-8") as Read_Pointer:load_json =json.loads( Read_Pointer.read() )group_obj = load_json.get("HostGroup")# 循环所有字典中的组for each in range(0, len(group_obj)):list_name = str(list(group_obj[each].keys())[0])# 先来寻找到需要删除的主机组if (list_name == group_name):tmp = group_obj[each]# 寻找指定组中的指定列表val = list(tmp.values())[0]for x in range(0, len(val)):if (val[x] == uuid):print("[*] 搜索UUID: {} 索引值: {}".format(val[x], x))# 将要删除的UUID弹出列表val.pop(x)# 将弹出后的列表重新复制到主机组中group_obj[each][list_name] = val# 保存弹出后的列表到序列中with open(self.database_path, "w", encoding="utf-8") as write_fp:dump_json = json.dumps(load_json)write_fp.write(dump_json)print("[+] 从主机组 {} 弹出UUID {} 完成".format(group_name, uuid))return 0return 0# 输出所有主机组和全部节点信息def ShowAllGroup(self):with open(self.database_path, "r", encoding="utf-8") as Read_Pointer:load_json = json.loads( Read_Pointer.read() )group_obj = load_json.get("HostGroup")# 循环解析所有组,并解析出UUID所对应的主机地址等信息for each in range(0, len(group_obj)):for k, v in group_obj[each].items():print("-" * 140)print("主机组: {}".format(k))print("-" * 140)for each in range(0, len(v)):# print("--> UUID: {}".format(v[each]))# 循环判断,拿着组内UUID判断是否存在,如果存在则打印出主机详细信息base_obj = load_json.get("HostList")for x in range(0, len(base_obj)):if (v[each] == base_obj[x][0]):print("UUID: {0:6} \t 主机地址: {1:15} \t 主机账号: {2:15} \t 主机密码: {3:15} \t 端口: {4:5} \t".format(base_obj[x][0], base_obj[x][1], base_obj[x][2], base_obj[x][3],base_obj[x][4]))print("\n")# 只显示所有的主机组,包括组中主机数def ShowGroup(self):with open(self.database_path, "r", encoding="utf-8") as Read_Pointer:load_json = json.loads( Read_Pointer.read() )group_obj = load_json.get("HostGroup")print("-" * 80)print("{0:20} \t {1:5} \t {2:100}".format("主机组名","主机数","主机列表"))print("-" * 80)for each in range(0,len(group_obj)):for k,v in group_obj[each].items():print("{0:20} \t {1:5} \t {2:100}".format(k,str(len(v)), str(v)))print()return 0# 对指定的主机组进行Ping测试def PingGroup(self,group_name):with open(self.database_path, "r", encoding="utf-8") as Read_Pointer:load_json = json.loads( Read_Pointer.read() )group_obj = load_json.get("HostGroup")# 循环遍历主机列表for each in range(0, len(group_obj)):for k, v in group_obj[each].items():# 寻找主机组,找到后提取出所有的Valueif (k == group_name):item_list = v# 再循环,拿着v的值对base进行循环,提取出其中的用户名密码等for val in range(0, len(item_list)):# 得到循环列表:print(item_list[val])base_obj = load_json.get("HostList")# 循环base表中的计数器for base_count in range(0, len(base_obj)):# 判断base表中是否存在指定UUID,如果存在则输出其值if (base_obj[base_count][0] == item_list[val]):print("地址: {} \t 用户名: {} [ok]".format(base_obj[base_count][1],base_obj[base_count][2]))
if __name__ == "__main__":db = AdminDataBase("database.json")while True:try:cmd = str(input("[LyShell] # ")).split()if (cmd == ""):continueelif (cmd[0] == "exit"):exit(1)elif (cmd[0] == "clear"):os.system("cls")elif(cmd[0] == "Init"):db.InitDatabase()elif(cmd[0] == "ShowHostList"):db.ShowHostList()elif(cmd[0] == "ShowGroup"):db.ShowGroup()elif(cmd[0] == "ShowAllGroup"):db.ShowAllGroup()elif(cmd[0] == "AddHost" or cmd[0] == "ModifyHost"):if (len(cmd) - 1 >= 5):uuid = str(cmd[1]).split("=")[1]address = str(cmd[2]).split("=")[1]username = str(cmd[3]).split("=")[1]password = str(cmd[4]).split("=")[1]port = str(cmd[5]).split("=")[1]if cmd[0] == "AddHost":db.AddHost(uuid,address,username,password,port)elif cmd[0] == "ModifyHost":db.ModifyHost(uuid,address,username,password,port)elif(cmd[0] == "DeleteHost"):if(len(cmd)-1 >= 1):uuid = str(cmd[1]).split("=")[1]db.DeleteHost(uuid)elif(cmd[0] == "AddHostGroup"):group_name = str(cmd[1]).split("=")[1]db.AddHostGroup(group_name)elif(cmd[0] == "DeleteHostGroup"):group_name = str(cmd[1]).split("=")[1]db.DeleteHostGroup(group_name)elif(cmd[0] == "AddHostGroupOnUUID"):group_name = str(cmd[1]).split("=")[1]uuid = str(cmd[2]).split("=")[1]db.AddHostGroupOnUUID(group_name,uuid)elif(cmd[0] == "DelHostGroupOnUUID"):group_name = str(cmd[1]).split("=")[1]uuid = str(cmd[2]).split("=")[1]db.DeleteHostGroupOnUUID(group_name,uuid)elif(cmd[0] == "PingGroup"):group_name = str(cmd[1]).split("=")[1]db.PingGroup(group_name)elif (cmd[0] == "help"):print("By: LyShark")else:print("Not Command")except Exception:continue

使用案例

管理数据库(AdminDataBase)中的主机信息和主机分组信息。用户通过输入命令来执行不同的操作,如初始化数据库、显示主机列表、添加主机、修改主机信息、删除主机等。

以下是代码的主要功能和命令列表:

  • 初始化数据库:Init
  • 显示主机列表:ShowHostList
  • 显示主机分组:ShowGroup
  • 显示所有主机分组:ShowAllGroup
  • 添加主机:AddHost
  • 修改主机信息:ModifyHost
  • 删除主机:DeleteHost
  • 添加主机分组:AddHostGroup
  • 删除主机分组:DeleteHostGroup
  • 将主机添加到指定分组:AddHostGroupOnUUID
  • 从指定分组删除主机:DelHostGroupOnUUID
  • 按组执行 Ping 操作:PingGroup
  • 清屏:clear
  • 退出程序:exit
  • 帮助:help

Init

初次使用需要执行本命令,对数据库文件进行写出,如下所示;

ShowHostList

用于输出当前主机列表信息,如下图所示;

ShowGroup

用于输出当前主机组,如下图所示;

ShowAllGroup

用于输出所有的主机组以及组内的主机详细信息,如下图所示;

AddHost

添加一个新的主机记录,如下图所示;

ModifyHost

修改一个已有的主机记录,此处以UUID作为修改条件,如下图所示;

DeleteHost

根据一个UUID唯一标识,删除一个已存在的主机记录,如下图所示;

AddHostGroup

新增一个组名,默认会携带1000为初始主机,如下图所示;

DeleteHostGroup

删除一整个主机组,如下图所示;

AddHostGroupOnUUID

根据UUID号将特定主机添加到特定组内,如下图所示;

DelHostGroupOnUUID

根据主机组名,删除特定的UUID,如下图所示;

PingGroup

对特定主机组执行Ping功能测试,此处可以扩展,如下图所示;

总结部分

该案例只是用于学习如何灵活运用JSON实现数据的增删改查,其实在实战中意义不大,因为完全可以使用SQLite这类精简数据库,此案例只是本人为了熟悉JSON的增删改查而写的一个Demo工具。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/198475.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【解决方案】环保设备用电与电网数据集中展示平台的应用与研究

摘 要:近年来,信息化不断推进,政府工作方式以及职能不断改革,许多省级环保部门开展环保与信息技术的融合,用于推进环保的发展。本文基于环境监测研究省级环保与电网数据集中展示平台的应用。环境监测是环保工作的重要组…

读书笔记-《数据结构与算法》-摘要1[数据结构]

文章目录 [数据结构]1. String - 字符串2. Linked List - 链表2.1 链表的基本操作2.1.1 反转链表单向链表双向链表 2.1.2 删除链表中的某个节点2.1.3 链表指针的鲁棒性2.1.4 快慢指针 3. Binary Tree - 二叉树3.1 树的遍历3.2 Binary Search Tree - 二叉查找树 4. Queue - 队列…

JSP入门+EL表达式+JSTL标签

1.JSP&#xff1a; 1.指令 2.注释 3.内置对象 2.MVC开发模式 3.EL表达式 4.JSTL标签 5.三层架构 ## JSP&#xff1a; 1.指令 *用于配置JSP页面&#xff0c;导入资源文件 *格式&#xff1a;<% 指令名称 属性名1属性值1 属性名2属性值2 .......%> *分类&#xff1…

格雷希尔帮助仪器仪表测试时快速密封的G60C系列接头其优势有哪些

仪器仪表在工业领域中扮演着重要的角色&#xff0c;如&#xff1a;压力表&#xff0c;压力传感器、压力变送器、压力开关、压力歧管等这些&#xff0c;在工业领域中都是随处可见的&#xff0c;其数据的精度直接影响着产品在生产过程中的质量和安全性&#xff1b;因此&#xff0…

食品行业研究:金枪鱼产业发展及市场消费分析

金枪鱼是无污染、高档、美味、安全、健康的绿色海洋动物食品&#xff0c;是国际营养协会推荐的世界三大营养鱼种之一 ,它凭借较高的经济价值、较广的分布范围、丰富的资源储量等优势&#xff0c;成为当今世界远洋渔业发展的关注重点和国际水产品贸易的主要鱼种。 金枪鱼类是高度…

3分钟,全方面了解透明oled拼接屏

透明OLED拼接屏是一种先进的显示技术&#xff0c;它具有透明度高、色彩鲜艳、轻薄柔韧、拼接灵活、功耗低、寿命长等特点。在商业、教育、展示、娱乐等领域&#xff0c;透明OLED拼接屏的应用越来越广泛。 在商业领域&#xff0c;透明OLED拼接屏可以作为商品展示柜&#xff0c;通…

系统运维工具KSysAK——让运维回归简单

系统运维工具KSysAK——让运维回归简单 1.基本信息 1.1概述 系统异常定位分析工具KSysAK是云峦操作系统研发及运维人员总结开发及运维经验&#xff0c;设计和研发的多个运维工具的集合&#xff0c;可以覆盖系统的日常监控、线上问题诊断和系统故障修复等常见运维场景。 工具…

从一个bug认识 Spring 单例模式

大家好&#xff0c;我是风筝&#xff0c;公众号「古时的风筝」 谁还没在 Spring 里栽过跟头呢&#xff0c;从哪儿跌倒&#xff0c;就从哪儿睡一会儿&#xff0c;然后再爬起来。 讲点儿武德 这是由一个真实的 bug 引起的&#xff0c;bug 产生的原因就是忽略了 Spring Bean 的…

网络层之无分类编址CIDR(内涵计算例题)

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

初学vue3与ts:element-plus的警告(Extraneous non-props attributes (ref_key) ...)

用了vue3与ts&#xff0c;ui我就选了element-plus element-plus官网&#xff1a;https://element-plus.org/zh-CN/ element-plus官网(国内镜像站点)&#xff1a;https://element-plus.gitee.io/zh-CN/ 国内镜像站点如果进不去的话&#xff0c;在element-plus官网最下面的链接-&…

Jupyter Notebook中设置Cell主题

1. 获取本机Jupyter的配置目录 C:\Users\Administrator>jupyter --data-dir C:\Users\Administrator\AppData\Roaming\jupyter2. 进入获取的目录&#xff0c;创建指定路径 C:\Users\Administrator>cd C:\Users\Administrator\AppData\Roaming\jupyter C:\Users\Adminis…

TikTok新闻视角:短视频如何改变信息传递方式?

随着数字时代的不断发展&#xff0c;信息传递的方式也在不断演变。近年来&#xff0c;短视频平台TikTok崭露头角&#xff0c;通过其独特的15秒短视频形式&#xff0c;逐渐在新闻传播领域占据一席之地。本文将深入探讨TikTok在新闻视角下是如何改变信息传递方式的&#xff0c;以…

计算机毕设:基于机器学习的生物医学语音检测识别 附完整代码数据可直接运行

项目视频讲解: 基于机器学习的生物医学语音检测识别 完整代码数据可直接运行_哔哩哔哩_bilibili 运行效果图: 数据展示: 完整代码: #导入python的 numpy matplotlib pandas库 import pandas as pd import numpy as np import matplotlib.pyplot as plt #绘图 import se…

jupyter notebook中添加内核kernel

step1 检查环境中是否有kernel python -m ipykernel --versionstep2 若没有kernel&#xff0c;则需要安装 kernel conda install ipykernel -i https://pypi.tuna.tsinghua.edu.cn/simplestep3 查看已添加的内核 jupyter kernelspec liststep4 添加内核 python -m ipykerne…

学习php中使用composer下载安装firebase/php-jwt 以及调用方法

学习php中使用composer下载安装firebase/php-jwt 以及调用方法 1、安装firebase/php-jwt2、封装jwt类 1、安装firebase/php-jwt composer require firebase/php-jwt安装好以后出现以下文件: 2、封装jwt类 根据所使用的php框架&#xff0c;在指定目录创建 Token.php <?ph…

外贸建站要国外服务器吗?海外服务器推荐?

外贸建站如何选国外服务器&#xff1f;海洋建站用什么服务器好&#xff1f; 外贸建站已经成为企业拓展国际市场的一项重要举措。然而&#xff0c;一个关键问题摆在许多企业面前&#xff1a;外贸建站是否需要选择国外服务器呢&#xff1f;这个问题涉及到多方面的考虑因素&#…

智能优化算法应用:基于吉萨金字塔建造算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于吉萨金字塔建造算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于吉萨金字塔建造算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.吉萨金字塔建造算法4.实验参数设…

航空复合材料行业分析:预计2028年全球市场规模将达3725.28亿元

航空复合材料是由多种材料层面组合而成的&#xff0c;在冷热不均的环境中&#xff0c;各个组成材料之间的温度承受度不同很容易引起部件损坏等情况的发生&#xff0c;因此随着复合材料在通用航空中应用的增加&#xff0c;航空复合材料维修市场已形成一定规模。目前&#xff0c;…

Node.js入门指南(完结)

目录 接口 介绍 RESTful json-server 接口测试工具 会话控制 介绍 cookie session token 上一篇文章我们介绍了MongoDB&#xff0c;这一篇文章是Node.js入门指南的最后一篇啦&#xff01;主要介绍接口以及会话控制。 接口 介绍 接口是前后端通信的桥梁 &#xff0…

【Unity动画】Unity 动画播放的流程

本文以2D为案例&#xff0c;讲解Unity 播放动画的流程 准备和导入2D动画资源 外部导入序列帧生成的 Unity内部制作的 外部导入的3D动画 2.创建动画过程 打开时间轴Ctrl6 选中场景中的一个未来需要播放动画的物体 回到时间轴点击Create一个新动画片段 拖动2D动画资源放入…