Gorm 的关联查询

背景介绍

gorm 与 mybatis-plus 、hibernate 等 ORM 框架一样,为了应对查询场景居多的现象,支持原生 sql 和 api 两种方式读数据库。

gorm 原生 sql 参见:https://gorm.io/docs/sql_builder.html。

gorm 提供的 api 支持关联插入、关联查询、关联更新、关联删除等功能。这篇文章对各种类型关联查询做以介绍。

关联类型

所谓关联查询就是:在执行查询操作时,如果对象的某个字段也是对象,那就将内部对象也一并查出。以前的做法是先查外围对象,再查内部对象,在内存中组装后返回给前端。

实现关联查询的核心是:依据业务理清楚关联类型以及外键应该放在哪里,在建对象的时候采用标签方式把外键和关联字段格式写正确

gorm 有默认使用类名+ID 作为默认外键,但是不建议这么使用。推荐使用标签指定外键和关联列,看起来清晰明了,出错少。

belong to (多对一)

链接:https://gorm.io/docs/belongs_to.html

使用场景如:一个员工属于一个公司,但一个公司可以有多个员工。在这种场景下,外键在 User 中,关联到 Company 的主键。

// foreignKey 标签显式指定外键。
// references 标签显式指定外键的关联字段。

type User struct {
	gorm.Model
	Name      string
	CompanyID int
	Company   Company `gorm:"foreignKey:CompanyID;references:ID"`
}

type Company struct {
	ID   int
	Name string
}

对应的表信息如下:

CREATE TABLE `users` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `created_at` datetime(3) DEFAULT NULL,
  `updated_at` datetime(3) DEFAULT NULL,
  `deleted_at` datetime(3) DEFAULT NULL,
  `name` longtext,
  `company_id` bigint DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_users_deleted_at` (`deleted_at`),
  KEY `fk_users_company` (`company_id`),
  CONSTRAINT `fk_users_company` FOREIGN KEY (`company_id`) REFERENCES `companies` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
-- 外键 company_id 关联到 companies 的 id 字段。

CREATE TABLE `companies` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `name` longtext,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

关联查询:
Preloading 就是在外围对象时关联上要查的内部对象。至于怎么关联的,全靠外键。


// 在查 user 对象时将其关联的 compancy 信息一并查出来。
db.Model(&User{}).Preload("Company").Find(&result, "name = ?", user.Name)
data, _ := json.Marshal(result)
println(string(data))

// {"ID":1,"CreatedAt":"2023-12-11T16:57:09.452+08:00","UpdatedAt":"2023-12-11T16:57:09.452+08:00","DeletedAt":null,"Name":"amos","CompanyID":12,"Company":{"ID":12,"Name":"google"}}

完整代码:

package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

func main() {
	source := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=true&loc=Local",
		"USERNAME", "PASSWORD", "127.0.0.1", 3306, "test")
	sqlDB, _ := sql.Open("mysql", source)
	db, _ := gorm.Open(mysql.New(mysql.Config{
		Conn: sqlDB,
	}), &gorm.Config{})

	// 创建表
	db.AutoMigrate(&User{}, &Company{})

	// 因为已经指定了约束关系,User.companyId 字段会自动被 Company.ID 字段填充。
	user := User{
		Model: gorm.Model{},
		Name:  "amos",
		Company: Company{
			ID:   12,
			Name: "google",
		},
	}
	
	// 关联插入。在插入 user 记录时,也插入 compancy 记录。
	db.Create(&user)

	var result User
	db.Model(&User{}).Preload("Company").Find(&result, "name = ?", user.Name)
	data, _ := json.Marshal(result)
	println(string(data))
}

type User struct {
	gorm.Model
	Name      string
	CompanyID int
	Company   Company `gorm:"foreignKey:CompanyID;references:ID"`
}

type Company struct {
	ID   int
	Name string
}

has one (一对一)

链接:https://gorm.io/docs/has_one.html

使用场景如:一个用户只能办理一张信用卡。此时外键写法比较随意,外键既可以放在 User 中,也可以放在 CreditCard 中。

// 外键放在 CreditCard 中。
type User struct {
	gorm.Model
	CreditCard   CreditCard `gorm:"foreignKey:UserID;references:ID"`
}

type CreditCard struct {
	gorm.Model
	Number string
	UserID uint
}

// --------------------------------------

// 外键放在 User 中。
type User struct {
	gorm.Model
	CreditCardId uint
	CreditCard   CreditCard `gorm:"foreignKey:CreditCardId;references:ID"`
}

type CreditCard struct {
	gorm.Model
	Number string
}

表:

--- 外键放在 CreditCard 中。
CREATE TABLE `credit_cards` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `created_at` datetime(3) DEFAULT NULL,
  `updated_at` datetime(3) DEFAULT NULL,
  `deleted_at` datetime(3) DEFAULT NULL,
  `number` longtext,
  `user_id` bigint unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_credit_cards_deleted_at` (`deleted_at`),
  KEY `fk_users_credit_card` (`user_id`),
  CONSTRAINT `fk_users_credit_card` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

------------------------------------------------------------------------------------

--- 外键放在 User 中。
CREATE TABLE `users` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `created_at` datetime(3) DEFAULT NULL,
  `updated_at` datetime(3) DEFAULT NULL,
  `deleted_at` datetime(3) DEFAULT NULL,
  `credit_card_id` bigint unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_users_deleted_at` (`deleted_at`),
  KEY `fk_users_credit_card` (`credit_card_id`),
  CONSTRAINT `fk_users_credit_card` FOREIGN KEY (`credit_card_id`) REFERENCES `credit_cards` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

关联查询:

user := User{
		Model: gorm.Model{ID: 1},
		CreditCard: CreditCard{
			Number: "374738728629",
		},
	}

	db.Create(&user)

	var result User
	db.Model(&User{}).Preload("CreditCard").Find(&result, "ID = ?", user.ID)
	data, _ := json.Marshal(result)
	println(string(data))

/*
{
    "ID":1,
    "CreatedAt":"2023-12-11T17:37:03.935+08:00",
    "UpdatedAt":"2023-12-11T17:37:03.935+08:00",
    "DeletedAt":null,
    "CreditCard":{
        "ID":1,
        "CreatedAt":"2023-12-11T17:37:03.936+08:00",
        "UpdatedAt":"2023-12-11T17:37:03.936+08:00",
        "DeletedAt":null,
        "Number":"374738728629",
        "UserID":1
    }
}
*/

has many (一对多)

参考链接:https://gorm.io/docs/has_many.html

使用场景如:一个用户有持有多张信用卡。外键在 CreditCard 中。

type User struct {
  gorm.Model
  MemberNumber string
  CreditCards  []CreditCard `gorm:"foreignKey:UserNumber;references:MemberNumber"`
}

type CreditCard struct {
  gorm.Model
  Number     string
  UserNumber string
}

关联查询

owner := User{
		Model:        gorm.Model{},
		MemberNumber: "2",
		CreditCards: []CreditCard{
			{
				Model:  gorm.Model{},
				Number: "1",
			},
			{
				Model:  gorm.Model{},
				Number: "2",
			},
		},
	}

	db.Create(&owner)

	var result User
	db.Model(&User{}).Preload("CreditCards").Find(&result, "member_number = ?", "2")
	data, _ := json.Marshal(result)
	println(string(data))

/*
{
    "ID":1,
    "CreatedAt":"2023-12-11T19:45:48.533+08:00",
    "UpdatedAt":"2023-12-11T19:45:48.533+08:00",
    "DeletedAt":null,
    "MemberNumber":"2",
    "CreditCards":[
        {
            "ID":1,
            "CreatedAt":"2023-12-11T19:45:48.534+08:00",
            "UpdatedAt":"2023-12-11T19:45:48.534+08:00",
            "DeletedAt":null,
            "Number":"1",
            "UserNumber":"2"
        },
        {
            "ID":2,
            "CreatedAt":"2023-12-11T19:45:48.534+08:00",
            "UpdatedAt":"2023-12-11T19:45:48.534+08:00",
            "DeletedAt":null,
            "Number":"2",
            "UserNumber":"2"
        }
    ]
}
*/

many to many (多对多)

链接:https://gorm.io/docs/many_to_many.html

使用场景如:一个学生可以选多门课,一门课也可以被多个学生选择。在该场景下,学生和课程的主键必须存在,因为 gorm 还要再生成一张关联表。

// many2many 标签表示多对多关联关系
// Student2Course 是生成的关联表名字。
// Student 和 Course 各自的主键必须存在,最好显式指定。

type Student struct {
	SId  int `gorm:"primary_key"`
	SNo  int
	Name string
	Sex  string
	Age  int
	Course []Course `gorm:"many2many:Student2Course"`
}

type Course struct {
	CId         int `gorm:"primary_key"`
	CName       string
	TeacherName string
	Room        string
}

CREATE TABLE `students` (
  `s_id` bigint NOT NULL AUTO_INCREMENT,
  `s_no` bigint DEFAULT NULL,
  `name` longtext,
  `sex` longtext,
  `age` bigint DEFAULT NULL,
  PRIMARY KEY (`s_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

CREATE TABLE `Courses` (
  `c_id` bigint NOT NULL AUTO_INCREMENT,
  `c_name` longtext,
  `teacher_name` longtext,
  `room` longtext,
  PRIMARY KEY (`c_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

CREATE TABLE `student2_courses` (
  `student_s_id` bigint NOT NULL,
  `course_c_id` bigint NOT NULL,
  PRIMARY KEY (`student_s_id`,`course_c_id`),
  KEY `fk_student2_courses_course` (`course_c_id`),
  CONSTRAINT `fk_student2_courses_course` FOREIGN KEY (`course_c_id`) REFERENCES `courses` (`c_id`),
  CONSTRAINT `fk_student2_courses_student` FOREIGN KEY (`student_s_id`) REFERENCES `students` (`s_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

-- 约束条件都在生成的关联表里。

关联查询:

stu1 := models.Student{
		SNo:  10010,
		Name: "amos",
		Sex:  "male",
		Age:  18,
		Course: []models.Course{
			{
				CName:       "match",
				TeacherName: "Mr.lube",
				Room:        "No1",
			},
			{
				CName:       "Physics",
				TeacherName: "Morris.li",
				Room:        "No2",
			},
		},
	}

	stu2 := models.Student{
		SNo:  10011,
		Name: "sam",
		Sex:  "male",
		Age:  19,
		Course: []models.Course{
			{
				CName:       "match",
				TeacherName: "Mr.lube",
				Room:        "No1",
			},
			{
				CName:       "Physics",
				TeacherName: "Morris.li",
				Room:        "No2",
			},
		},
	}

	db.Create(&stu1)
	db.Create(&stu2)
	
	var result []*models.Student
	db.Model(&models.Student{}).Preload("Course").Find(&result)
	bytes, _ := json.Marshal(result)
	println(string(bytes))

/*
[{"SId":1,"SNo":10010,"Name":"amos","Sex":"male","Age":18,"Course":[{"CId":1,"CName":"match","TeacherName":"Mr.lube","Room":"No1"},{"CId":2,"CName":"Physics","TeacherName":"Morris.li","Room":"No2"}]},{"SId":2,"SNo":10011,"Name":"sam","Sex":"male","Age":19,"Course":[{"CId":3,"CName":"match","TeacherName":"Mr.lube","Room":"No1"},{"CId":4,"CName":"Physics","TeacherName":"Morris.li","Room":"No2"}]}]

*/

Polymorphism Association 多态关联

它主要解决一张表怎么与其他多张表关联的问题。

在社交媒体中有如下应用:

  • 一个用户可以发表评论。
  • 一个图片也可以被评论。

怎么处理评论和用户、博客、图片之间的关系。比如:查用户时怎么关联到他的评论。在比如:如果后期再来个博客的评论,该怎么处理?

/*
1. 
2. polymorphicValue 表示多态类型的值,如果不显式指定,默认是类名。
*/

// 评论
type Comment struct {
    gorm.Model
    Content     string
    OwnerID     uint
    OwnerType   string 
}
// 用户
type person struct {
    gorm.Model
    Name       string
    Comments   []Comment `gorm:"polymorphic:Owner;polymorphicValue:user"`
}
// 图片
type Image struct {
    gorm.Model
~~~~    URL        string
    Comments   []Comment `gorm:"polymorphic:Owner;polymorphicValue:image"`
}
  1. polymorphic:Owner:polymorphic 是多态关键字,Owner 表示“所有者”,会将“所有者”的 ID 填充到 Comment.OwnerID 字段上。
  2. polymorphicValue:user:polymorphicValue 表示多态类型,user 表示类型的值,会将 “user” 值填充到 Comment.OwnerType 字段上。如果 polymorphicValue 缺失,则使用类型名填充。

Comments 表
在这里插入图片描述

people 表

在这里插入图片描述

images 表

在这里插入图片描述

关联查询

db.AutoMigrate(&person{}, &Image{}, &Comment{})

	user := person{
		Name: "John",
		Comments: []Comment{
			{Content: "Great post!"},
			{Content: "terrible post!"},
		},
	}

	image := Image{
		Model: gorm.Model{},
		URL:   "https://example.com/image.jpg",
		Comments: []Comment{
			{Content: "Nice image!"},
		},
	}

	db.Create(&user)
	db.Create(&image)

	var fetchedUser person
	db.Model(&person{}).Preload("Comments").Find(&fetchedUser, "ID = ?", user.ID)
	userBytes, _ := json.Marshal(fetchedUser)
	println(string(userBytes))
	// {"ID":1,"CreatedAt":"2023-12-11T21:45:08.457+08:00","UpdatedAt":"2023-12-11T21:45:08.457+08:00","DeletedAt":null,"Name":"John","Comments":[{"ID":1,"CreatedAt":"2023-12-11T21:45:08.458+08:00","UpdatedAt":"2023-12-11T21:45:08.458+08:00","DeletedAt":null,"Content":"Great post!","OwnerID":1,"OwnerType":"user"},{"ID":2,"CreatedAt":"2023-12-11T21:45:08.458+08:00","UpdatedAt":"2023-12-11T21:45:08.458+08:00","DeletedAt":null,"Content":"terrible post!","OwnerID":1,"OwnerType":"user"}]}

	var fetchedImage Image
	db.Model(&Image{}).Preload("Comments").Find(&fetchedImage, "ID = ?", image.ID)
	imageBytes, _ := json.Marshal(fetchedImage)
	println(string(imageBytes))
	// {"ID":1,"CreatedAt":"2023-12-11T21:45:08.459+08:00","UpdatedAt":"2023-12-11T21:45:08.459+08:00","DeletedAt":null,"URL":"https://example.com/image.jpg","Comments":[{"ID":3,"CreatedAt":"2023-12-11T21:45:08.459+08:00","UpdatedAt":"2023-12-11T21:45:08.459+08:00","DeletedAt":null,"Content":"Nice image!","OwnerID":1,"OwnerType":"image"}]}

如果后期来个视频的评论怎么处理?

创建新对象就可以,不用像以前一样新增列。

type Post struct {
    gorm.Model
    Title    string
    Content  string
    Comments []Comment `gorm:"polymorphic:Owner;polymorphicValue:post"`
}

异常现象

官网给的代码有 bug,有时候不能直接使用,可能是版本不一致。

异常 1:

BLOB/TEXT column 'user_number' used in key specification without a key len

解决办法:

type CreditCard struct {
	gorm.Model
	Number     string
	UserNumber string `gorm:"size:191"`
}

异常 2:

Failed to add the foreign key constraint. Missing index for constraint 'fk_card_owners_credit_cards' in the referenced table 'card_owners'

解决办法:

关联字段必须有索引。

type CardOwner struct {
	gorm.Model
	MemberNumber string       `gorm:"index"` # 添加索引
	CreditCards  []CreditCard `gorm:"foreignKey:UserNumber;references:MemberNumber"`
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Jmeter入门

一、下载jmeter 官网下载 下载之后解压,在目录/bin下面找到jmeter.bat双击之后即可启动Jmeter。 二、使用 如下左图,选择语言为中文,可以修改测试计划的名称。如下右图,添加线程组 添加线程组 添加http请求 路径传参方式 …

Linux——MySQL数据库系统

一、 MySQL的编译安装 1、准备工作 (1)为了避免发生端口冲突,程序冲突等现象,建议先查询MySQL软件的安装情况,确认没有使用以Rpm方式安装的mysql-server、mysql软件包,否则建议将其卸载 [rootlocalhost ~]…

mars3d加载arcgis发布的服务,⽀持4523坐标

问题 1.从这个服务地址加载,具体在哪⾥去转坐标呢? 加个 usePreCachedTilesIfAvailable:false 参数即可 坐标系为4490的arcgis影像服务图层,配置后瓦片加载不出来,没报错 甚至可以跳转 没有看出问题,或者测…

RK3568驱动指南|第八篇 设备树插件-第75章ConfigFS的核心数据结构

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工…

神由之星加入元宇宙产业委员会共谋数字发展新篇章

近年来,元宇宙产业呈现出飞速发展的趋势,成为全球范围内备受瞩目的新兴行业。在这个充满机遇与挑战的时代,常州神由之星数字信息产业发展有限公司凭借敏锐的洞察力和卓越的数字产品,迅速抓住元宇宙的发展势头,大力发展元宇宙业务,成为该领域内一颗冉冉升起的新星。 神由之星荣膺…

数据分享 I 全国市级商品房屋销售数据,shp/excel格式,2005-2020年数据

基本信息. 数据名称: 全国市级商品房屋销售数据 数据格式: Shp、excel 数据时间: 2005-2020年 数据几何类型: 面 数据坐标系: WGS84坐标系 数据来源:网络公开数据 数据字段: 序号字段名称字段说明1spxse商品房销售额(亿元&#xf…

优思学院|如何建立公司运营指标体系?如何推行六西格玛改进运营指标?

关键绩效指标 (KPI) 是测量您团队或组织朝重要商业目标进展表现如何的量化指标,组织会在多个层面使用 KPI,这视乎您想要追踪何指标而定,您可以设定全组织的、特定团队的、或甚至是个人 KPI。 良好的KPI能让公司管理者掌握组织的营运是否进度…

在设计和考虑建造室外雨水收集池时需要注意的因素

在设计和建造室外雨水收集池时,需要考虑以下因素: 地质条件:建造雨水收集池需要考虑到地质条件,例如土壤类型、地基承载能力等。这些因素可能对水池的建造和结构产生影响。 气候条件:不同地区的降雨量、湿度、气温等…

Spring基于xml半注解开发

目录 Component的使用 依赖注解的使用 非自定义Bean的注解开发 Component的使用 基本Bean注解&#xff0c;主要是使用注解的方式替代原有的xml的<bean>标签及其标签属性的配置&#xff0c;使用Component注解替代<bean>标签中的id以及class属性&#xff0c;而对…

node.js express mongoose用户建模、权限校验

目录 userModel.js 依赖引入 数据建模 中间件 模型方法 创建user model并导出 catchAsync.js authController.js 依赖引入 token生成 注册 登录 密码修改 userRoutes.js 路由设计 protect中间件 角色中间件 app.js userModel.js 依赖引入 const mongoose …

解决canvas清晰度问题devicePixelRatio

视频教程 解决canvas清晰度的问题【渡一教育】_哔哩哔哩_bilibili 检测网页本身是否缩放 ,即缩放倍率 window.devicePixelRatio 为了获得清晰图像,需要遵循以下公式 原始尺寸样式尺寸*缩放倍率 在项目中,canvas里的原始尺寸一般与css中的样式尺寸一样,所以在写js代码时,涉…

纯电超跑SUV获得2024中国年度性能车大奖 路特斯ELETRE实力几何?

2023年12月5日&#xff0c;“中国年度车”颁奖盛典在北京圆满落幕。路特斯首款纯电超跑SUV ELETRE ( 参数询价 ) 斩获“2024中国年度性能车”大奖&#xff0c;成为首次获此殊荣的纯电SUV车型。一台纯电SUV能获得年度性能车奖项&#xff0c;注定是件非常有看点的事&#xff0c;那…

17.(vue3.x+vite)组件间通信方式之作用域插槽

前端技术社区总目录(订阅之前请先查看该博客) 示例效果 作用域插槽 父组件中的插槽内容是无法访问到子组件中的数据的,而作用域插槽就是解决获取子组件数据。 父组件代码 <template><div><div>父组件--Hello World!</div><Child>

【普中开发板】基于51单片机电子钟闹钟设计( proteus仿真+程序+设计报告+讲解视频)

【普中开发板】基于51单片机电子钟闹钟数码管显示设计( proteus仿真程序设计报告讲解视频&#xff09; Proteus 仿真&#xff1a;Proteus 8.16 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;P03 51单片机电子钟闹钟 1. 主要功能&a…

RT-Thread Studio + STM32CubeMx 联合开发

RT-Thread Studio STM32CubeMx 联合开发 背景参考 背景 使用RTThreadNano开发工具&#xff1a; RTThread Studio&#xff1a;官方工具&#xff0c;对RTThread系统兼容最好&#xff0c;可以对不同的MCU平台进行开发&#xff0c;包括但不限于以下平台 STM32GD32IAR STM32CubeI…

mac 安装nvm以及切换node版本详细步骤

1、nvm介绍&#xff08;node版本管理工具&#xff09; nvm 可以让你通过命令行快速安装和使用不同版本的node 有时候项目太老&#xff0c;node版本太高,执行npm install命令会报错,可以借助nvm切换低版本的node。 2、安装nvm 在终端执行安装命令 curl -o- https://raw.gith…

Vue router深入学习

Vue router深入学习 一、单页应用程序介绍 1.概念 单页应用程序&#xff1a;SPA【Single Page Application】是指所有的功能都在一个html页面上实现 2.具体示例 单页应用网站&#xff1a; 网易云音乐 https://music.163.com/ 多页应用网站&#xff1a;京东 https://jd.co…

销售技巧培训之如何提升化妆品销售技巧

销售技巧培训之如何提升化妆品销售技巧 一、引言 在当今竞争激烈的化妆品市场&#xff0c;销售人员需要掌握一定的技巧才能吸引顾客&#xff0c;提高销售业绩。本文将通过实际案例&#xff0c;探讨化妆品销售的有效技巧&#xff0c;帮助销售人员提升业绩。 二、案例分析 案…

jstree组件的使用详细教程,部分案例( PHP / fastAdmin )

jstree 组件的使用。 简介&#xff1a;JsTree是一个jquery的插件&#xff0c;它提交一个非常友好并且强大的交互性的树&#xff0c;并且是完全免费或开源的&#xff08;MIT 许可&#xff09;。Jstree技持Html 或 json格式的的数据&#xff0c; 或者是ajax方式的动态请求加载数…