当前位置: 首页 > news >正文

Coze源码分析-资源库-编辑知识库-后端源码-IDL/API层

前言

本文将深入分析Coze Studio项目中用户编辑知识库功能的后端实现。当用户登录Coze平台后,点击"资源库" → 接着在表格中点击要编辑的知识库行,触发的是一个完整的知识库资源编辑流程。知识库作为AI应用开发的重要数据基础,其编辑操作涉及权限验证、数据更新和多个后端服务层的协同工作。通过源码解读,我们将深入理解知识库编辑功能在整个Coze Studio后端架构中的设计思路和技术实现细节。

项目架构概览

知识库编辑功能架构设计

Coze Studio的知识库编辑功能采用了经典的分层架构模式,专门针对知识库资源的安全编辑进行了优化设计。整个架构围绕知识库的权限验证、数据更新和事件通知展开:

┌─────────────────────────────────────────────────────────────┐
│                    IDL接口定义层                             │
│  ┌─────────────┐  ┌─────────────┐    ┌─────────────┐        │
│  │ base.thrift │  │knowledge.   │    │ api.thrift  │        │
│  │             │  │thrift       │    │             │        │
│  │             │  │             │    │             │        │
│  └─────────────┘  └─────────────┘    └─────────────┘        │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                    API网关层                                 │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │   Handler   │  │   Router    │  │ Middleware  │          │
│  │   处理器     │  │   路由      │  │   中间件     │          │
│  └─────────────┘  └─────────────┘  └─────────────┘          │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                   应用服务层                                 │
│  ┌─────────────────────────────────────────────────────┐    │
│  │           KnowledgeApplicationService                │    │
│  │               UpdateKnowledge                        │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                   领域服务层                                 │
│  ┌─────────────────────────────────────────────────────┐    │
│  │              knowledgeServiceImpl                    │    │
│  │                ┌─────────────────┐                  │    │
│  │                │UpdateKnowledge  │                  │    │
│  │                │                 │                  │    │
│  │                └─────────────────┘                  │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                   数据访问层                                 │
│  ┌─────────────────────────────────────────────────────┐    │
│  │              KnowledgeRepository                    │    │
│  │  ┌──── ─────── ──── ──┐  ┌─────────────────────────┐│    │
│  │  │KnowledgeDAO        │  │knowledge.gen.go         ││    │
│  │  │UpdateKnowledge     │  │GORM Generated Code      ││    │
│  │  └──── ─────── ─── ───┘  └─────────────────────────┘│    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                   基础设施层                                 │
│              ┌─ ─ ─── ─ ── ── ─ ─ ─┐                        │
│              │       gorm.DB       │                        │
│              │ eventBus            │                        │
│              └── ─ ── ── ─ ── ── ─ ┘                        │
└─────────────────────────────────────────────────────────────┘↓
┌─────────────────────────────────────────────────────────────┐
│                   存储服务层                                 │
│  ┌─────────────────────────────────────────────────────┐    │
│  │       MySQL数据库       事件总线                     │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘

插件编辑流程核心组件

API路由映射:

  • POST /api/knowledge_api/check_and_lock_knowledge_edit - 检查并锁定知识库以进行编辑
  • POST /api/knowledge_api/update_knowledge_meta - 更新知识库元数据
  • POST /api/knowledge_api/unlock_knowledge_edit - 解锁知识库编辑

核心数据模型:

// 文件位置:backend/api/model/crossdomain/knowledge/knowledge.go
type KnowledgeInfo struct {ID           int64KnowledgeType   api.KnowledgeTypeSpaceID      int64CreatorID    int64APPID        *int64RefProductID *int64 // for product knowledgeCoverImageURI *stringVisibility   *stringVersion      *stringVersionDesc  *stringCreatedAt    int64UpdatedAt    int64MetaInfo     *KnowledgeMetaInfoDocFormat    *DocFormatT
}// 文件位置:backend/api/model/crossdomain/knowledge/document.go
type DocumentInfo struct {ID           int64KnowledgeID        int64Name            stringDesc            stringContentType     stringContentURI      stringActivatedStatus ActivatedStatusIndexStatus     IndexStatusCreatedAt       int64UpdatedAt       int64MetaData        map[string]interface{}IndexContent    *IndexContentT
}

1. IDL接口定义层

IDL基础类型定义(base.thrift)

文件位置:idl/base.thrift
核心代码:

namespace py base
namespace go base
namespace java com.bytedance.thrift.basestruct TrafficEnv {1: bool   Open = false,2: string Env  = ""   ,
}struct Base {1:          string             LogID      = "",2:          string             Caller     = "",3:          string             Addr       = "",4:          string             Client     = "",5: optional TrafficEnv         TrafficEnv     ,6: optional map<string,string> Extra          ,
}struct BaseResp {1:          string             StatusMessage = "",2:          i32                StatusCode    = 0 ,3: optional map<string,string> Extra             ,
}

文件作用:
定义了Coze Studio项目中所有接口的基础数据结构,作为其他IDL文件的依赖基础。

知识库编辑接口定义(knowledge.thrift)

文件位置:idl/data/knowledge/knowledge.thrift

当Coze用户登录平台后点击"资源库" → 接着在表格中点击要编辑的知识库行时,前端会调用知识库编辑相关的接口。该文件定义了知识库编辑的核心数据结构和接口。

更新知识库接口
struct UpdateDatasetRequest {1  : required string    dataset_id,2  : optional string    name,3  : optional string    description,4  : optional string    cover_url,5  : optional string    owner_id,6  : optional string    visibility,7  : optional string    tags,8  : optional i64       version,9  : optional string    user_id,255: optional base.Base Base,
}struct UpdateDatasetResponse {1  : required i32       code,2  : required string    msg,3  : optional UpdateDatasetResult data,255: optional base.BaseResp BaseResp,
}struct UpdateDatasetResult {1  : string    dataset_id,2  : i64       updated_at,3  : i64       version,
}

知识库服务接口定义(knowledge_svc.thrift)

文件位置:idl/service/knowledge_svc.thrift

include "data/knowledge/knowledge.thrift"namespace py knowledge_svc
namespace go knowledge_svc
namespace java com.bytedance.thrift.knowledge_svcservice KnowledgeService {knowledge.UpdateDatasetResponse UpdateDataset(1: knowledge.UpdateDatasetRequest request),
}// API路由映射
// @api /api/knowledge/update3  :          i32           edit_version,255: optional base.BaseResp BaseResp    ,
}
解锁知识库编辑接口
struct UnlockKnowledgeEditRequest {1  : required i64    knowledge_id (api.body = "knowledge_id", api.js_conv = "str"),255: optional base.Base Base                                                   ,
}struct UnlockKnowledgeEditResponse {1  : required i32           code       ,2  : required string        msg        ,3  : required bool          released ,255: optional base.BaseResp BaseResp                       ,
}

知识库编辑服务接口(knowledge_edit.thrift)

文件位置:idl/knowledge/knowledge_edit.thrift

该文件定义了KnowledgeEditService服务的核心接口,包括知识库管理的服务接口定义。

KnowledgeEditService服务定义
service KnowledgeEditService {CheckAndLockKnowledgeEditResponse CheckAndLockKnowledgeEdit(1: CheckAndLockKnowledgeEditRequest request)(api.post='/api/knowledge_api/check_and_lock_knowledge_edit', api.category="knowledge", api.gen_path="knowledge", )UnlockKnowledgeEditResponse UnlockKnowledgeEdit(1: UnlockKnowledgeEditRequest request)(api.post='/api/knowledge_api/unlock_knowledge_edit', api.category="knowledge", api.gen_path="knowledge")UpdateKnowledgeMetaResponse UpdateKnowledgeMeta(1: UpdateKnowledgeMetaRequest request) (api.post = '/api/knowledge_api/update_knowledge_meta', api.category = "knowledge")// 其他服务接口...
}

知识库接口路由映射说明:

  • CheckAndLockKnowledgeEdit: POST /api/knowledge_api/check_and_lock_knowledge_edit - 检查并锁定知识库以进行编辑

  • UpdateKnowledgeMeta: POST /api/knowledge_api/update_knowledge_meta - 更新知识库元数据

  • UnlockKnowledgeEdit: POST /api/knowledge_api/unlock_knowledge_edit - 解锁知识库编辑

  • 数据结构设计: CheckAndLockKnowledgeEditRequest包含知识库ID字段;UpdateKnowledgeMetaRequest包含知识库ID、名称、描述、可见性等可更新字段;UnlockKnowledgeEditRequest包含知识库ID字段

  • 编辑操作: 支持通过UI界面编辑知识库,包括基本信息更新、可见性配置修改等

IDL主API服务聚合文件(api.thrift)

文件位置:idl/api.thrift

该文件是整个Coze项目的API服务聚合入口点,负责将所有业务模块的IDL服务定义统一聚合,为代码生成工具提供完整的服务接口定义。

核心代码:


include "./knowledge/knowledge_edit.thrift"namespace go coze// 知识库编辑核心服务聚合
service KnowledgeEditService extends knowledge_edit.KnowledgeEditService {}
// 其他业务服务聚合

知识库接口聚合说明:
通过 service KnowledgeEditService extends knowledge_edit.KnowledgeEditService {} 聚合定义,api.thrift将knowledge_edit.thrift中定义的所有知识库相关接口统一暴露.

2. API网关层

接口定义-knowledge.go文件详细分析

文件位置:backend\api\model\data\knowledge\knowledge.go
核心代码:

type KnowledgeService interface {UpdateDataset(ctx context.Context, request *UpdateDatasetRequest) (r *UpdateDatasetResponse, err error)}
知识库相关接口模型定义

当Coze用户登录平台后点击"资源库" → 接着在表格中点击要编辑的知识库行时,前端会调用知识库编辑相关接口来编辑知识库资源。

UpdateDatasetRequest 更新知识库请求结构体

type UpdateDatasetRequest struct {// 知识库IDDatasetID string `thrift:"dataset_id,1,required" form:"dataset_id,required" json:"dataset_id,required" query:"dataset_id,required"`// 知识库名称Name string `thrift:"name,2" form:"name" json:"name" query:"name"`// 知识库描述Description string `thrift:"description,3" form:"description" json:"description" query:"description"`// 封面URLCoverUrl string `thrift:"cover_url,4" form:"cover_url" json:"cover_url" query:"cover_url"`// 所有者IDOwnerId string `thrift:"owner_id,5" form:"owner_id" json:"owner_id" query:"owner_id"`// 可见性Visibility string `thrift:"visibility,6" form:"visibility" json:"visibility" query:"visibility"`// 标签Tags string `thrift:"tags,7" form:"tags" json:"tags" query:"tags"`// 版本号Version int64 `thrift:"version,8" form:"version" json:"version" query:"version"`// 用户IDUserId string `thrift:"user_id,9" form:"user_id" json:"user_id" query:"user_id"`Base   *base.Base `thrift:"Base,255" form:"Base" json:"Base" query:"Base"`
}

UpdateDatasetResponse 更新知识库响应结构体

type UpdateDatasetResponse struct {// 状态码Code int32 `thrift:"code,1,required" json:"code"`// 状态信息Msg string `thrift:"msg,2,required" json:"msg"`// 响应数据Data *UpdateDatasetResult `thrift:"data,3" json:"data"`// 基础响应信息BaseResp *base.BaseResp `thrift:"BaseResp,255" json:"BaseResp"`
}

UpdateDatasetResult 更新知识库结果结构体

type UpdateDatasetResult struct {// 知识库IDDatasetId string `thrift:"dataset_id,1" json:"dataset_id"`// 更新时间戳UpdatedAt int64 `thrift:"updated_at,2" json:"updated_at"`// 版本号Version int64 `thrift:"version,3" json:"version"`
}
接口功能说明

业务功能

  • 知识库信息更新:根据用户输入更新知识库的基本信息,如名称、描述、封面等
  • 权限验证:确保只有有权限的用户才能编辑知识库
  • 数据存储:将更新后的知识库信息持久化存储
  • 版本管理:维护知识库的版本号,确保数据一致性
  • 事件通知:触发知识库更新事件,通知相关服务

技术特性

  • 类型安全:使用强类型定义确保知识库数据的一致性
  • 多格式支持:支持thrift、form、json、query等多种序列化格式
  • 参数验证:通过required标记确保必要参数的完整性
  • 统一响应:遵循统一的响应格式规范

文件作用
由thriftgo自动生成的Go代码文件,基于knowledge.thrift IDL定义生成对应的Go结构体和接口,提供类型安全的知识库API模型。该文件实现了完整的Thrift RPC通信机制,包括客户端调用、服务端处理、序列化/反序列化等功能,确保了知识库服务间的可靠通信。

知识库接口处理器实现

文件位置:backend/api/handler/coze/knowledge_service.go

该文件包含了用户登录后点击"资源库" → 接着在表格中点击要编辑的知识库行功能的核心API接口处理器,主要负责处理知识库资源的编辑功能。

更新知识库处理器
// UpdateDataset .
// @router /api/knowledge/update [POST]
func UpdateDataset(ctx context.Context, c *app.RequestContext) {var err errorvar req knowledge.UpdateDatasetRequesterr = c.BindAndValidate(&req)if err != nil {invalidParamRequestResponse(c, err.Error())return}if req.DatasetID == "" {invalidParamRequestResponse(c, "datasetID is invalid")return}resp, err := knowledge.KnowledgeApplicationSVC.UpdateKnowledge(ctx, &req)if err != nil {internalServerErrorResponse(ctx, c, err)return}c.JSON(consts.StatusOK, resp)
}
func UpdateKnowledgeMeta(ctx context.Context, c *app.RequestContext) {var err errorvar req knowledge_edit.UpdateKnowledgeMetaRequesterr = c.BindAndValidate(&req)if err != nil {invalidParamRequestResponse(c, err.Error())return}if req.KnowledgeID <= 0 {invalidParamRequestResponse(c, "knowledgeID is invalid")return}if req.Name != nil && *req.Name == "" {invalidParamRequestResponse(c, "knowledge name is invalid")return}if req.Desc != nil && *req.Desc == "" {invalidParamRequestResponse(c, "knowledge desc is invalid")return}if req.Visibility != nil && (*req.Visibility == "" || len(*req.Visibility) > 512) {invalidParamRequestResponse(c, "knowledge visibility is invalid")return}resp, err := knowledge.KnowledgeApplicationSVC.UpdateKnowledgeMeta(ctx, &req)if err != nil {internalServerErrorResponse(ctx, c, err)return}c.JSON(consts.StatusOK, resp)
}
解锁知识库编辑处理器
// UnlockKnowledgeEdit .
// @router /api/knowledge_api/unlock_knowledge_edit [POST]
func UnlockKnowledgeEdit(ctx context.Context, c *app.RequestContext) {var err errorvar req knowledge_edit.UnlockKnowledgeEditRequesterr = c.BindAndValidate(&req)if err != nil {invalidParamRequestResponse(c, err.Error())return}resp, err := knowledge.KnowledgeApplicationSVC.UnlockKnowledgeEdit(ctx, &req)if err != nil {internalServerErrorResponse(ctx, c, err)return}c.JSON(consts.StatusOK, resp)
}

实现功能

  1. 参数验证:验证知识库ID、名称、描述、可见性等参数的有效性
  2. 业务调用:调用KnowledgeApplicationSVC应用服务层的相应方法处理知识库编辑业务逻辑
  3. 错误处理:统一的错误处理机制,包括参数错误和内部服务错误
  4. 响应返回:返回标准化的操作响应结果

参数校验逻辑

  • 知识库ID验证:确保知识库ID大于0,防止无效的编辑操作
  • 知识库名称验证:确保更新的知识库名称不为空
  • 知识库描述验证:确保更新的知识库描述不为空
  • 可见性验证:确保知识库可见性设置长度不超过512字符

路由注册实现-api.go文件详细分析

文件位置:backend/api/router/coze/api.go

该文件是Coze Studio后端的核心路由注册文件,由hertz generator自动生成,负责将所有HTTP API接口路由与对应的处理函数进行绑定和注册。对于知识库编辑功能,构建了专门的路由结构:

/api/knowledge_api/check_and_lock_knowledge_edit [POST]
├── rootMw() # 根级中间件
├── _apiMw() # API组中间件
├── _knowledge_apiMw() # 知识库API组中间件
├── _checkandlockknowledgeeditMw() # 检查并锁定知识库编辑接口专用中间件
└── coze.CheckAndLockKnowledgeEdit # 检查并锁定知识库编辑处理函数/api/knowledge_api/update_knowledge_meta [POST]
├── rootMw() # 根级中间件
├── _apiMw() # API组中间件
├── _knowledge_apiMw() # 知识库API组中间件
├── _updateknowledgemetaMw() # 更新知识库元数据接口专用中间件
└── coze.UpdateKnowledgeMeta # 更新知识库元数据处理函数/api/knowledge_api/unlock_knowledge_edit [POST]
├── rootMw() # 根级中间件
├── _apiMw() # API组中间件
├── _knowledge_apiMw() # 知识库API组中间件
├── _unlockknowledgeeditMw() # 解锁知识库编辑接口专用中间件
└── coze.UnlockKnowledgeEdit # 解锁知识库编辑处理函数

核心代码:

{_knowledge_api := _api.Group("/knowledge_api", _knowledge_apiMw()...)_knowledge_api.POST("/check_and_lock_knowledge_edit", append(_checkandlockknowledgeeditMw(), coze.CheckAndLockKnowledgeEdit)...)_knowledge_api.POST("/update_knowledge_meta", append(_updateknowledgemetaMw(), coze.UpdateKnowledgeMeta)...)_knowledge_api.POST("/unlock_knowledge_edit", append(_unlockknowledgeeditMw(), coze.UnlockKnowledgeEdit)...)// 其他知识库相关路由...
}

3. 应用服务层

KnowledgeApplicationService 应用服务层概述

KnowledgeApplicationService是知识库编辑功能的核心应用服务层组件,负责协调领域服务和数据访问层,处理知识库编辑的业务逻辑。当用户登录Coze平台后点击"资源库",并在表格中点击要编辑的知识库行时,该服务将处理所有相关的业务逻辑。

更新知识库实现

当用户在编辑界面修改知识库信息并保存时,应用服务层通过UpdateKnowledge方法处理更新请求:

// UpdateKnowledge 更新知识库信息
func (k *KnowledgeApplicationService) UpdateKnowledge(ctx context.Context, req *knowledge.UpdateDatasetRequest) (*knowledge.UpdateDatasetResponse, error) {// 获取当前时间戳now := time.Now().UnixMilli()// 参数验证if req.DatasetID == "" {return nil, errors.New("datasetID is required")}// 构建领域服务层的更新请求updateReq := service.UpdateKnowledgeRequest{KnowledgeID: req.GetDatasetID(),Name:        &req.Name,Description: &req.Description,CoverUrl:    &req.CoverUrl,Visibility:  &req.Visibility,Tags:        &req.Tags,}// 调用领域服务层更新知识库err := k.DomainSVC.UpdateKnowledge(ctx, &updateReq)if err != nil {logs.CtxErrorf(ctx, "update knowledge failed, datasetID: %s, err: %v", req.GetDatasetID(), err)return nil, err}// 发布资源变更事件err = k.eventBus.Publish(ctx, &event.KnowledgeUpdatedEvent{KnowledgeID: req.GetDatasetID(),UserID:      req.GetUserID(),UpdatedAt:   now,})if err != nil {logs.CtxErrorf(ctx, "publish knowledge updated event failed, err: %v", err)// 事件发布失败不影响主流程}// 返回成功响应return &knowledge.UpdateDatasetResponse{Code: consts.StatusOK,Msg:  "success",Data: &knowledge.UpdateDatasetResult{DatasetId:  req.GetDatasetID(),UpdatedAt:  now,Version:    req.GetVersion() + 1,},}, nil
}

文档操作实现

知识库编辑不仅包括基本信息更新,还包括文档级别的操作:

// CreateDocument 创建文档
func (k *KnowledgeApplicationService) CreateDocument(ctx context.Context, req *knowledge.CreateDocumentRequest) (*knowledge.CreateDocumentResponse, error) {// 获取用户IDuid := ctxutil.GetUIDFromCtx(ctx)if uid == nil {return nil, errorx.New(errno.ErrKnowledgePermissionCode, "unauthorized")}// 验证知识库权限hasPermission, err := k.checkKnowledgePermission(ctx, req.GetDatasetID(), *uid)if err != nil {return nil, err}if !hasPermission {return nil, errorx.New(errno.ErrKnowledgePermissionCode, "no permission")}// 构建文档请求docReq := service.CreateDocumentRequest{KnowledgeID: req.GetDatasetID(),Title:       req.GetTitle(),Content:     req.GetContent(),Type:        req.GetType(),CreatorID:   *uid,}// 调用领域服务创建文档resp, err := k.DomainSVC.CreateDocument(ctx, &docReq)if err != nil {logs.CtxErrorf(ctx, "create document failed, err: %v", err)return nil, err}return &knowledge.CreateDocumentResponse{Code: consts.StatusOK,Msg:  "success",Data: &knowledge.CreateDocumentResult{DocumentId: resp.DocumentID,},}, nil
}// UpdateDocument 更新文档
func (k *KnowledgeApplicationService) UpdateDocument(ctx context.Context, req *knowledge.UpdateDocumentRequest) (*knowledge.UpdateDocumentResponse, error) {// 实现文档更新逻辑...// 包括权限验证、参数验证、调用领域服务等
}

应用服务层工作流程

当用户在Coze平台编辑知识库时,应用服务层的完整工作流程如下:

  1. 用户交互阶段

    • 用户登录Coze平台
    • 点击「资源库」进入知识库列表
    • 在表格中点击要编辑的知识库行
    • 前端展示知识库编辑界面
  2. 编辑提交阶段

    • 用户修改知识库名称、描述、封面等信息
    • 点击保存按钮提交修改
    • 前端调用/api/knowledge/update接口
    • API网关层将请求转发到应用服务层
  3. 业务处理阶段

    • 应用服务层接收请求并进行参数验证
    • 验证用户是否有权限编辑该知识库
    • 构建领域服务请求对象
    • 调用领域服务层的UpdateKnowledge方法
  4. 事件发布阶段

    • 知识库更新成功后,发布知识更新事件
    • 缓存更新、搜索索引更新等订阅服务接收事件并更新数据
    • 返回格式化的响应给API网关层
    • 前端接收到响应并更新界面

核心业务逻辑与协作

应用服务层在知识库编辑过程中处理以下核心业务逻辑:

  1. 参数验证:验证请求参数的合法性和完整性
  2. 权限校验:确保用户有权限编辑指定的知识库
  3. 请求转换:将API层请求转换为领域服务层可用的格式
  4. 领域协调:调用领域服务层完成实际的业务操作
  5. 事件发布:发布领域事件,通知相关服务进行后续处理
  6. 响应封装:将处理结果封装为标准响应格式

应用服务层采用了依赖注入模式,通过构造函数注入领域服务、事件总线等依赖组件,实现了松耦合的设计,便于测试和维护。

http://www.dtcms.com/a/446117.html

相关文章:

  • 机器学习周报十六
  • 怎么免费制作企业网站找人做个网站大概多少钱
  • 凡科建站自助建站平台定制手机壳的网站
  • 实战 | 使用 Chrome 开发者工具修改网页源码跳过前端校验
  • 汕头网站时优化php 网站版面素材
  • 生活小记呀
  • 身份治理技术的演进之路:从手动管理到智能自动化
  • 嵌入式第六十六天(I2C子系统架构)
  • 长春网络建站益阳做网站
  • 在线网站备案网页设计师培训费用图片大全
  • stp root primary 概念及题目
  • Photoshop - Photoshop 工具栏(4)套索工具
  • 公司网站建设会计你分录苏州网站建设
  • 关于重新运行后台程序nohup python3的办法(一)
  • ICT 数字测试原理 6 - -VCL 测试结构
  • 第七章:桥接模式 - 抽象与实现的桥梁大师
  • 短视频推荐的底层逻辑:大数据如何 “读懂” 你的每一次滑动
  • 嘉兴市建设工程监理协会网站学做美食看哪个网站
  • 《SpringBoot入门实战:从HelloWorld到RESTful接口(支持GET/POST/PUT/DELETE,附Git版本控制)》
  • 信用网站一体化建设网页制作大宝库
  • gRPC从0到1系列【19】
  • 嵌入式Linux Qt触摸屏问题诊断与解决报告
  • gRPC从0到1系列【20】
  • CTFHub 信息泄露通关笔记10:SVN泄露(2种方法)
  • 手机网站开发环境搭建网站建设个人网银
  • 使用 jintellitype 库在 Java 程序中实现监听 Windows 全局快捷键(热键)
  • Python驱动Ksycopg2连接和使用Kingbase:国产数据库实战指南
  • 广州网站网站建设福建建站公司
  • ⚡ arm 32位嵌入式 Linux 系统移植 QT 程序
  • VR大空间资料 02 —— 常用Body IK对比