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

Coze源码分析-资源库-删除数据库-后端源码-领域服务/数据访问层

4. 领域服务层

数据库领域服务层架构

数据库领域服务层是Coze Studio中处理数据库业务逻辑的核心层,负责数据库资源的删除、管理和业务规则实现。该层采用领域驱动设计(DDD)模式,将业务逻辑与数据访问分离,确保代码的可维护性和可扩展性。

数据库领域服务接口定义

数据库领域服务接口定义了数据库管理的核心业务能力,包括数据库资源的完整生命周期管理。

type DatabaseService interface {// 删除数据库DeleteDatabase(ctx context.Context, req *DeleteDatabaseRequest) error// 其他数据库管理方法CreateDatabase(ctx context.Context, req *CreateDatabaseRequest) (*CreateDatabaseResponse, error)GetDatabase(ctx context.Context, req *GetDatabaseRequest) (*GetDatabaseResponse, error)UpdateDatabase(ctx context.Context, req *UpdateDatabaseRequest) error
}

核心接口功能

  1. 数据库资源管理:创建、获取、更新、删除用户自定义的数据库资源
  2. 删除操作核心:DeleteDatabase方法是删除数据库的核心业务接口
  3. 事务管理:确保数据库删除操作的原子性和一致性
  4. 业务规则封装:封装数据库相关的业务逻辑和验证规则
  5. 数据完整性保障:确保数据库及其关联数据的完整删除
数据库领域服务实现

文件位置:backend/domain/memory/database/service/database_impl.go

数据库服务实现类包含了所有数据库相关业务逻辑的具体实现,负责处理数据库删除的核心业务逻辑,包括在线库和草稿库的同时删除。

func (d databaseService) DeleteDatabase(ctx context.Context, req *DeleteDatabaseRequest) error {onlineInfo, err := d.onlineDAO.Get(ctx, req.ID)if err != nil {return fmt.Errorf("get online database info failed: %v", err)}draftInfo, err := d.draftDAO.Get(ctx, onlineInfo.GetDraftID())if err != nil {return fmt.Errorf("get draft database info failed: %v", err)}tx := query.Use(d.db).Begin()if tx.Error != nil {return fmt.Errorf("start transaction failed, %v", tx.Error)}defer func() {if r := recover(); r != nil {e := tx.Rollback()if e != nil {logs.CtxErrorf(ctx, "rollback failed, err=%v", e)}err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))return}if err != nil {e := tx.Rollback()if e != nil {logs.CtxErrorf(ctx, "rollback failed, err=%v", e)}}}()err = d.draftDAO.DeleteWithTX(ctx, tx, draftInfo.ID)if err != nil {return fmt.Errorf("delete draft database info failed: %v", err)}err = d.onlineDAO.DeleteWithTX(ctx, tx, onlineInfo.ID)if err != nil {return fmt.Errorf("delete online database info failed: %v", err)}err = tx.Commit()if err != nil {return fmt.Errorf("commit transaction failed: %v", err)}// delete draft physical tableif draftInfo.ActualTableName != "" {_, err = d.rdb.DropTable(ctx, &rdb.DropTableRequest{TableName: draftInfo.ActualTableName,})// 错误处理...}// delete online physical tableif onlineInfo.ActualTableName != "" {_, err = d.rdb.DropTable(ctx, &rdb.DropTableRequest{TableName: onlineInfo.ActualTableName,})// 错误处理...}return nil
}

删除操作实现特点

  1. 事务保障:使用数据库事务确保删除操作的原子性和一致性
  2. 完整删除:同时删除在线库和草稿库的元数据和物理表
  3. 异常处理:完善的panic恢复和事务回滚机制
  4. 资源清理:删除数据库相关的物理表资源
  5. 错误包装:详细的错误信息,便于问题定位和调试

DeleteDatabase方法详解

  • 参数:接收DeleteDatabaseRequest结构体,包含数据库ID
  • 处理流程
    1. 获取在线数据库信息
    2. 获取对应草稿数据库信息
    3. 开启事务进行原子操作
    4. 删除草稿数据库信息
    5. 删除在线数据库信息
    6. 提交事务
    7. 删除物理表资源
  • 错误处理:每个步骤都有详细的错误捕获和包装
数据库实体定义

数据库实体定义了数据库资源的核心数据结构,包含了数据库的所有关键属性。

type Database struct {ID             int64         // 数据库唯一标识AppID          int64         // 所属应用IDSpaceID        int64         // 所属空间ID,支持多租户隔离CreatorID      int64         // 创建者IDTableName      string        // 表名FieldList      []*FieldItem  // 字段列表ActualTableName string       // 实际物理表名DraftID        *int64        // 草稿IDRwMode         BotTableRWMode // 读写模式Status         BotTableStatus // 状态CreatedAt      int64         // 创建时间戳UpdatedAt      int64         // 更新时间戳
}

实体设计特点

  1. 基础信息:包含ID、应用ID、空间ID等基本属性
  2. 表结构定义:通过FieldList定义数据库表结构
  3. 多租户支持:SpaceID字段支持多租户和空间隔离
  4. 创建者管理:CreatorID字段支持数据库所有权管理
  5. 状态管理:Status字段支持数据库的生命周期管理
  6. 物理映射:ActualTableName字段记录实际物理表名
  7. 草稿关联:DraftID字段关联对应的草稿版本
  8. 读写控制:RwMode字段控制数据库的读写权限
  9. 时间追踪:CreatedAt和UpdatedAt支持时间追踪和审计

5. 数据访问层

5.1 仓储接口定义

数据库仓储接口

数据库仓储接口定义了数据库资源的持久化操作能力,包括数据库的增删改查等核心功能。

type DatabaseRepository interface {// DeleteDatabase 删除数据库DeleteDatabase(ctx context.Context, id int64) error// GetDatabase 获取数据库信息GetDatabase(ctx context.Context, id int64) (*DatabaseInfo, error)// 其他CRUD方法...
}

删除方法特点

  • 事务删除:DeleteDatabase方法支持事务操作,确保数据一致性
  • 上下文支持:支持context.Context进行请求链路追踪
  • 错误处理:返回error类型,便于上层进行错误处理
  • ID定位:通过唯一id精确定位要删除的数据库资源

5.2 数据访问对象(DAO)

数据库删除的具体实现

数据库删除操作涉及在线库和草稿库的同步删除,需要通过事务确保数据一致性:

func (d *databaseRepoImpl) DeleteDatabase(ctx context.Context, id int64) (err error) {onlineInfo, err := d.onlineDAO.Get(ctx, id)if err != nil {return fmt.Errorf("get online database info failed: %v", err)}draftInfo, err := d.draftDAO.Get(ctx, onlineInfo.GetDraftID())if err != nil {return fmt.Errorf("get draft database info failed: %v", err)}tx := query.Use(d.db).Begin()if tx.Error != nil {return fmt.Errorf("start transaction failed, %v", tx.Error)}defer func() {if r := recover(); r != nil {e := tx.Rollback()if e != nil {logs.CtxErrorf(ctx, "rollback failed, err=%v", e)}err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))return}if err != nil {e := tx.Rollback()if e != nil {logs.CtxErrorf(ctx, "rollback failed, err=%v", e)}}}()err = d.draftDAO.DeleteWithTX(ctx, tx, draftInfo.ID)if err != nil {return fmt.Errorf("delete draft database info failed: %v", err)}err = d.onlineDAO.DeleteWithTX(ctx, tx, onlineInfo.ID)if err != nil {return fmt.Errorf("delete online database info failed: %v", err)}err = tx.Commit()if err != nil {return fmt.Errorf("commit transaction failed: %v", err)}// 删除物理表资源if draftInfo.ActualTableName != "" {_, err = d.rdb.DropTable(ctx, &rdb.DropTableRequest{TableName: draftInfo.ActualTableName,})// 错误处理...}if onlineInfo.ActualTableName != "" {_, err = d.rdb.DropTable(ctx, &rdb.DropTableRequest{TableName: onlineInfo.ActualTableName,})// 错误处理...}return nil
}

删除操作的关键特点

  1. 事务保证:使用数据库事务确保所有删除操作的原子性
  2. 完整删除:同时删除在线库和草稿库的元数据和物理表
  3. 异常处理:完善的panic恢复和事务回滚机制
  4. 资源清理:删除数据库相关的物理表资源
  5. 错误包装:详细的错误信息,便于问题定位和调试

删除涉及的数据表

  • bot_table_info:数据库元数据表
  • bot_table_info_draft:数据库草稿表
  • 物理表:实际存储数据的物理表
DatabaseDAO结构体

DatabaseDAO是数据库数据访问的具体实现,负责与数据库进行交互,处理数据库资源的持久化操作。

package dalimport ("context""fmt""gorm.io/gorm""github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
)type DatabaseDAO struct {db *gorm.DBidGen idgen.IDGenerator
}func NewDatabaseDAO(db *gorm.DB, generator idgen.IDGenerator) *DatabaseDAO {return &DatabaseDAO{db: db,idGen: generator,}
}
数据库删除操作实现

删除数据库记录

func (d *DatabaseDAO) DeleteWithTX(ctx context.Context, tx *gorm.DB, id int64) (err error) {result := tx.WithContext(ctx).Where("id = ?", id).Delete(&DatabaseInfo{})if result.Error != nil {return fmt.Errorf("delete database in transaction failed: %v", result.Error)}if result.RowsAffected == 0 {return fmt.Errorf("database not found with id: %d", id)}return nil
}

获取数据库信息

func (d *DatabaseDAO) Get(ctx context.Context, id int64) (*DatabaseInfo, error) {var info DatabaseInforesult := d.db.WithContext(ctx).Where("id = ?", id).First(&info)if result.Error != nil {return nil, fmt.Errorf("get database failed: %v", result.Error)}return &info, nil
}
数据转换方法

数据库实体与数据模型转换

func (d *DatabaseDAO) databaseInfoDO2PO(database *entity.DatabaseInfo) *model.DatabaseInfo {fieldListJSON, _ := json.Marshal(database.FieldList)return &model.DatabaseInfo{ID:             database.ID,AppID:          database.AppID,SpaceID:        database.SpaceID,CreatorID:      database.CreatorID,TableName:      database.TableName,FieldList:      string(fieldListJSON),ActualTableName: database.ActualTableName,DraftID:        database.DraftID,RwMode:         int32(database.RwMode),Status:         int32(database.Status),}
}

数据模型转实体

type databaseInfoPO model.DatabaseInfofunc (d databaseInfoPO) ToDO() *entity.DatabaseInfo {var fieldList []*entity.FieldItem_ = json.Unmarshal([]byte(d.FieldList), &fieldList)database := &entity.DatabaseInfo{ID:             d.ID,AppID:          d.AppID,SpaceID:        d.SpaceID,CreatorID:      d.CreatorID,TableName:      d.TableName,FieldList:      fieldList,ActualTableName: d.ActualTableName,DraftID:        d.DraftID,RwMode:         entity.BotTableRWMode(d.RwMode),Status:         entity.BotTableStatus(d.Status),CreatedAt:      d.CreatedAt,UpdatedAt:      d.UpdatedAt,}return database
}

删除操作特点

  1. 事务删除:DeleteWithTX方法支持事务操作,确保数据一致性
  2. 精确定位:通过id精确定位要删除的数据库资源
  3. 结果验证:验证删除操作是否实际影响了数据行
  4. 物理删除:执行物理删除操作,从数据库中彻底移除记录
  5. 资源清理:同时清理物理表资源,避免资源泄漏

删除数据库的完整数据访问流程

在删除数据库的场景中,数据访问层的操作流程如下:

  1. 获取在线库信息:查询在线数据库的元数据信息
  2. 获取草稿库信息:根据在线库关联的DraftID查询草稿库信息
  3. 事务开始:开启数据库事务,确保删除操作的原子性
  4. 删除草稿库:在事务中删除草稿库记录
  5. 删除在线库:在事务中删除在线库记录
  6. 事务提交:所有删除操作成功后提交事务
  7. 删除物理表:提交事务后,删除相关的物理表资源
  8. 错误回滚:任何操作失败时回滚事务,保证数据一致性

这种设计确保了删除操作的安全性、可靠性和数据完整性。

数据访问层删除操作总结

删除数据库在数据访问层的实现具有以下特点:

  1. 事务保证:所有元数据删除操作在事务中执行,确保数据一致性
  2. 完整删除:同时删除在线库、草稿库和物理表资源
  3. 验证机制:验证删除操作是否成功,确保资源确实被删除
  4. 错误处理:完善的错误处理和事务回滚机制
  5. 资源清理:彻底清理相关资源,避免资源泄漏
  6. 性能优化:通过精确的WHERE条件,确保删除操作的高效执行

5.3 数据库数据模型

DatabaseInfo数据模型

数据库数据模型定义了数据库资源在数据库中的存储结构,使用GORM标签进行ORM映射。

// DatabaseInfo 数据库信息模型
type DatabaseInfo struct {ID             int64  `gorm:"column:id;primaryKey;autoIncrement;comment:数据库ID" json:"id"`AppID          int64  `gorm:"column:app_id;not null;index:idx_appid;comment:应用ID" json:"app_id"`SpaceID        int64  `gorm:"column:space_id;not null;index:idx_spaceid;comment:空间ID" json:"space_id"`CreatorID      int64  `gorm:"column:creator_id;not null;index:idx_creatorid;comment:创建者ID" json:"creator_id"`TableName      string `gorm:"column:table_name;not null;type:varchar(100);comment:表名" json:"table_name"`FieldList      string `gorm:"column:field_list;type:text;comment:字段列表" json:"field_list"`ActualTableName string `gorm:"column:actual_table_name;type:varchar(255);comment:实际表名" json:"actual_table_name"`DraftID        *int64 `gorm:"column:draft_id;index:idx_draftid;comment:草稿ID" json:"draft_id"`RwMode         int32  `gorm:"column:rw_mode;default:0;comment:读写模式" json:"rw_mode"`Status         int32  `gorm:"column:status;default:0;comment:状态" json:"status"`CreatedAt      int64  `gorm:"column:created_at;not null;autoCreateTime;comment:创建时间" json:"created_at"`UpdatedAt      int64  `gorm:"column:updated_at;not null;autoUpdateTime;comment:更新时间" json:"updated_at"`
}// TableName 指定表名
func (*DatabaseInfo) TableName() string {return "bot_table_info"
}

删除操作中的模型特点

  1. 主键定位:ID字段作为主键,是删除操作的核心定位字段,确保精确删除
  2. 索引优化:为AppID、SpaceID、CreatorID、DraftID字段建立索引,提高查询效率
  3. 关联字段:DraftID字段关联在线库和草稿库,支持级联删除
  4. 物理映射:ActualTableName字段记录实际物理表名,支持物理资源清理
  5. 类型约束:对字符串类型设置长度限制,确保数据完整性
  6. 默认值设置:为RwMode和Status字段设置默认值
  7. 时间戳自动管理:使用autoCreateTime和autoUpdateTime自动管理时间戳
  8. JSON序列化:通过json标签支持JSON序列化,便于API响应和日志记录

5.4 GORM生成的查询接口

GORM框架为数据库数据模型生成了丰富的查询接口,支持各种查询和操作场景。

// 根据ID查询
func (d *DatabaseDAO) GetByID(ctx context.Context, id int64) (*DatabaseInfo, error) {var info DatabaseInforesult := d.db.WithContext(ctx).First(&info, "id = ?", id)if result.Error != nil {return nil, result.Error}return &info, nil
}// 条件查询
func (d *DatabaseDAO) ListByCondition(ctx context.Context, condition map[string]interface{}, page, pageSize int) ([]*DatabaseInfo, error) {var infos []*DatabaseInfoquery := d.db.WithContext(ctx)// 添加查询条件for key, value := range condition {query = query.Where(key, value)}// 分页查询result := query.Offset((page - 1) * pageSize).Limit(pageSize).Find(&infos)if result.Error != nil {return nil, result.Error}return infos, nil
}

#### 查询接口定义
```go
type IWorkflowDraftDo interface {gen.SubQueryDebug() IWorkflowDraftDoWithContext(ctx context.Context) IWorkflowDraftDoWithResult(fc func(tx gen.Dao)) gen.ResultInfoReplaceDB(db *gorm.DB)ReadDB() IWorkflowDraftDoWriteDB() IWorkflowDraftDo// 删除操作相关方法Delete(conds ...gen.Condition) (gen.ResultInfo, error)Where(conds ...gen.Condition) IWorkflowDraftDo......
}

删除操作相关接口特点

  1. Delete方法:提供类型安全的删除操作,支持条件删除
  2. Where条件:支持复杂的删除条件构建,确保精确删除
  3. 上下文支持:WithContext方法支持请求上下文传递
  4. 事务支持:支持在事务中执行删除操作,确保数据一致性
  5. 调试支持:Debug方法便于删除操作的SQL调试和优化
5.5 统一查询入口

文件位置:backend\domain\workflow\internal\dal\query\gen.go

该文件为删除工作流操作提供了统一的查询入口和事务支持,确保删除操作的一致性和可靠性。

核心代码:

// Code generated by gorm.io/gen. DO NOT EDIT.package queryimport ("context""database/sql""gorm.io/gorm""gorm.io/gen""gorm.io/plugin/dbresolver"
)var (Q            = new(Query)WorkflowDraft *workflowDraft
)func SetDefault(db *gorm.DB, opts ...gen.DOOption) {*Q = *Use(db, opts...)WorkflowDraft = &Q.WorkflowDraft
}func Use(db *gorm.DB, opts ...gen.DOOption) *Query {return &Query{db:          db,PluginDraft: newPluginDraft(db, opts...),ToolDraft:   newToolDraft(db, opts...),}
}type Query struct {db *gorm.DBWorkflowDraft workflowDraft
}func (q *Query) Available() bool { return q.db != nil }func (q *Query) clone(db *gorm.DB) *Query {return &Query{db:          db,WorkflowDraft: q.WorkflowDraft.clone(db),}
}func (q *Query) ReadDB() *Query {return q.ReplaceDB(q.db.Clauses(dbresolver.Read))
}func (q *Query) WriteDB() *Query {return q.ReplaceDB(q.db.Clauses(dbresolver.Write))
}func (q *Query) ReplaceDB(db *gorm.DB) *Query {return &Query{db:          db,WorkflowDraft: q.WorkflowDraft.replaceDB(db),}
}type queryCtx struct {WorkflowDraft IWorkflowDraftDo
}func (q *Query) WithContext(ctx context.Context) *queryCtx {return &queryCtx{WorkflowDraft: q.WorkflowDraft.WithContext(ctx),}
}func (q *Query) Transaction(fc func(tx *Query) error, opts ...*sql.TxOptions) error {return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.clone(tx)) }, opts...)
}func (q *Query) Begin(opts ...*sql.TxOptions) *QueryTx {tx := q.db.Begin(opts...)return &QueryTx{Query: q.clone(tx), Error: tx.Error}
}type QueryTx struct {*QueryError error
}func (q *QueryTx) Commit() error {return q.db.Commit().Error
}func (q *QueryTx) Rollback() error {return q.db.Rollback().Error
}func (q *QueryTx) SavePoint(name string) error {return q.db.SavePoint(name).Error
}func (q *QueryTx) RollbackTo(name string) error {return q.db.RollbackTo(name).Error
}

删除操作查询入口特点

  1. 全局查询对象:提供全局的WorkflowDraft查询对象,便于删除操作的统一管理
  2. 事务支持:Transaction方法支持在事务中执行删除操作,确保数据一致性
  3. 读写分离:ReadDB和WriteDB方法支持数据库读写分离,删除操作使用WriteDB
  4. 上下文传递:WithContext方法支持请求上下文在删除操作中的传递
  5. 数据库切换:ReplaceDB方法支持动态切换数据库连接,便于多环境部署
  6. 事务管理:Begin、Commit、Rollback等方法提供完整的事务管理能力

5.6 数据访问层删除操作架构总结

删除工作流在数据访问层的实现体现了现代Go应用的最佳实践:

技术特点

  1. 类型安全:使用GORM Gen生成类型安全的查询接口,避免SQL注入和类型错误
  2. 分层设计:Repository接口抽象数据访问,DAO实现具体的数据库操作
  3. 错误处理:统一的错误码包装机制,便于上层进行错误分类和处理
  4. 事务支持:完整的事务支持,确保删除操作的原子性
  5. 性能优化:精确的WHERE条件和索引利用,确保删除操作的高效执行

安全保障

  1. 权限验证:通过OwnerID字段确保只有工作流所有者可以删除自己的工作流
  2. 存在性检查:删除前验证工作流是否存在,避免无效删除
  3. 物理删除:彻底从数据库中移除记录,确保数据清理的完整性
  4. 审计追踪:完整的时间戳记录,支持删除操作的审计和追踪

删除操作流程

  1. 接口调用:上层通过Repository接口调用DeleteDraftWorkflow方法
  2. 事务开启:开启数据库事务确保操作的原子性
  3. 删除操作:删除工作流数据
  4. 事务提交:删除操作成功后提交事务
  5. 错误处理:任何步骤失败都会回滚事务并返回错误

这种设计确保了删除工作流操作的安全性、可靠性和高性能,为上层业务逻辑提供了坚实的数据访问基础。

数据模型与查询文件依赖关系
数据库表结构 (schema.sql)(workflow_draft表)↓    gen_orm_query.go
模型文件 (model/workflow_draft.gen.go) - 生成模型↓
查询文件 (query/workflow_draft.gen.go) - 依赖对应模型↓
统一入口 (query/gen.go) - 依赖所有查询文件

数据访问层架构总结

分层架构

业务服务层 (Service)↓
仓储接口层 (Repository Interface)↓
数据访问层 (DAO Implementation)↓
GORM查询层 (Generated Query)↓
数据模型层 (Generated Model)↓
数据库层 (MySQL)

删除工作流在数据访问层的完整流程

  1. 接口定义WorkflowRepository.DeleteDraftWorkflow(ctx, ID) 定义删除操作契约
  2. DAO实现WorkflowDraftDAO.DeleteWithTX(tx, ID) 实现具体删除逻辑
  3. 事务管理:使用事务确保工作流数据的一致性删除
  4. 删除操作:执行工作流数据的删除操作
  5. 错误处理:包装删除异常为统一错误码
  6. 结果返回:删除成功返回nil,失败返回包装后的错误

设计优势

  1. 接口抽象:通过Repository接口实现数据访问的抽象化
  2. 代码生成:使用GORM Gen自动生成类型安全的查询代码
  3. 错误处理:统一的错误包装和处理机制
  4. 事务支持:通过context传递支持数据库事务
  5. 删除安全:通过ID精确定位,避免误删除操作
  6. 性能优化:合理的索引设计和查询优化
  7. 可测试性:清晰的分层结构便于单元测试
  8. 可维护性:代码生成减少手工编写,降低维护成本
  9. 单一职责:每个DAO类专注于单一实体的数据访问操作

删除操作的技术特点

  • 物理删除:当前实现为物理删除,直接从数据库中移除记录
  • 事务操作:使用数据库事务确保工作流数据的一致性删除
  • 索引优化:基于主键ID的删除操作,具有最佳的查询性能
  • 错误分类:通过错误码区分不同类型的删除异常
  • 审计支持:可通过数据库日志追踪删除操作的执行情况
http://www.dtcms.com/a/415740.html

相关文章:

  • 游戏网站平台大全游戏网网站团购活动页面怎么做
  • Elasticsearch 从入门到实战
  • 网站如何调用手机淘宝做淘宝客佛山品牌策划设计
  • 氛围编程有哪些成功案例?
  • 网站优化外包推荐衡水企业做网站多少钱
  • 有哪些网站程序重庆网站建设的意义
  • Android开发-应用广播
  • AI 算力加速指南:Figma AI/Canva AI 全场景优化,从 “闪退卡顿” 到 “流畅创作”(一)
  • C++/C#游戏开发引擎和2D/3D图形库
  • 企业网站建设课件商业招商网站
  • 上海网站建设sheji021抖音代运营多少钱
  • 快递网站模版建网站公司汽车六万公里是否累变速箱油
  • 搭建了虚拟局域网,飞牛NAS的防火墙还需要开吗?
  • 中小学网站建设探讨海外网络推广外包
  • 安徽网站设计流程xp系统没有lls组件可以做网站吗
  • Mac中XXX将对您的电脑造成伤害, 您应该将它移到废纸篓
  • 广州市做网站公司品牌展柜设计制作
  • 计算机视觉进阶教学之dlib库(二)
  • 石家庄网站制作方案衡阳seo排名
  • 网站推广怎么做关键词网站抓取诊断
  • 牛客算法基础noob54 斗兽棋
  • 网站上传文件 ftpwordpress cdn系统
  • 企业介绍微网站怎么做淄博网站排名优化
  • 多相DDC数据FIR抽取滤波实例
  • 免费制作网站服务器网页做网站的尺寸
  • Strassen算法详解实现
  • 【看房清单】
  • 使用Python的Pillow库将JPG图片转换为PNG格式
  • 如何制作自己的网站模版wordpress文件夹改名
  • 五年健康守护日 IP沉淀,顶固让品质与温度穿越行业周期