文档中心>智能创作

后台代码解读

最近更新时间:2023-07-12 14:23:22

我的收藏
该项目是为“短视频小程序解决方案所提供的后台 Demo”,主要开发语言为 TypeScript,使用 Koa 框架进行搭建,其中使用了丰富的第三方开源库,如 routing-controllersclass-validatortypeormtypedi 等。

配置文件

本项目使用 src/conf/config/moduleConfig.json 作为整个 Demo 服务的配置文件。开发者可以根据自身业务进行配置项的调整。
{
"port": 3000,
"db": {
"host":"localhost",
"username":"root",
"password":"vod@2020#DEMO",
"port":"3306",
"database":"short-video"
},
"secretId": "",
"secretKey": "",
"urlKey": "",
"wxAppConfig": {
"appId": "",
"appSecret": "",
}
}
配置项
描述
port
服务监听的端口号,默认为 3000
db
数据库配置。
db.host
数据库连接地址,默认为 localhost
db.username
数据库用户名,默认为 root
db.password
数据库密码,默认为 vod@2020#DEMO
db.port
数据库端口号,默认为 3306
db.database
数据库名,默认为 short-video
secretId
secretId 相当于用户名。API 密钥(SecretId/SecretKey),代表您的账号身份和所拥有的权限,本 Demo 主要用于生成上传签名。
secretKey
secretKey 相当于用户密码。API 密钥(SecretId/SecretKey),代表您的账号身份和所拥有的权限,本 Demo 主要用于生成上传签名。
urlKey
播放 URL 防盗链 Key,用于生成视频防盗链。默认为空。
wxAppConfig
微信小程序配置。
wxAppConfig.appId
微信小程序开发者 AppId。
wxAppConfig.appSecret
微信小程序开发者 AppSecret。

接口列表

HTTP 方法
接口路由
描述
POST
/ModifyPassword
修改密码。
POST
/ModifyUserInfo
修改用户信息。
POST
/GetUserInfo
拉取用户资料。
POST
/GetUploadSign
获取上传签名。
POST
/GetVideoList
获取视频列表。
POST
/GetVideoListByUser
根据用户获取视频列表。
POST
/DeleteVideo
删除视频。
POST
/WXAMPGetVideoList
获取发布到微信小程序的视频列表。
POST
/WXAMPLogin
微信小程序用户登录/注册。

代码解读

目录结构

|-- package.json
|-- src
| |-- conf
| |-- controller
| |-- dao
| |-- dto
| |-- entity
| |-- index.ts
| |-- service
| `-- util
`-- tsconfig.json
文件/目录
说明
该文件定义了这个项目所需要的各种依赖模块,以及项目的运行 Script 和配置信息(例如名称、版本、许可证等元数据)。
src
源代码目录。
src/conf
配置模块。
src/controller
控制器模块。接口的路由和处理定义在此模块,是每个接口处理的入口。
src/dao
数据访问模块。包含了对数据库的增删改查操作。
src/dto
数据传输对象模块。封装了每个接口的请求参数和参数校验。
src/entity
实体模块。封装了实体类与数据库表的映射关系(ORM)。
src/index.ts
程序的入口文件。
src/service
服务模块。封装了一系列服务类的方法。
src/util
工具模块。
编译 TypeScript 代码的配置文件。

模块介绍

本 Demo 主要包含配置、控制器、数据传输对象、实体、服务、工具等多个模块, 下面将分别介绍这些模块以及实现方式。

程序入口 index.ts

index.ts 是本 Demo 的程序入口文件。包含以下作用:
加载服务配置。
连接数据库。
通过 Koa 加载日志和解析 HTTP BODY 的中间件,注册控制器。
启动 HTTP Server ,监听服务请求。
说明
如果数据库连接出错,服务将启动失败。

配置模块 src/conf

该模块主要负责读取文件 moduleConfig.json 的配置信息,包括服务端口号、数据配置、secretId/secretKey 等信息。如果读取或解析配置文件失败, 则使用默认的配置信息。
模块文件
描述
整个 Demo 服务的配置文件。
config.ts
主要用于读取 moduleConfig.json 文件中的配置信息。

控制器模块 src/controller

该模块主要使用第三方库 routing-controllers 进行路由注册和请求处理,使用装饰器(decorator)代替 Koa 中传统的路由指定方式。Controller 类中的每个方法都对应一个业务接口,是接口处理的入口。
模块文件
描述
wxampAccount.ts
包含了 /WXAMPLogin小程序账户相关的接口实现。
callback.ts
包括了 /UploadCallback/AiContentReviewCallback等回调相关的接口实现。
index.ts
导出控制器类,以供程序入口文件(index.ts)进行注册。
media.ts
包含了 /WXAMPGetVideoList/GetVideoListByUser/DeleteVideo 等媒资相关的接口实现。
upload.ts
包含了 /GetUploadSign 上传相关的接口实现。
user.ts
包含了 /ModifyUserInfo/GetUserInfo 等用户相关的接口实现。
play.ts
包含了 /PlayVideo等播放相关的接口实现。
下面以 src/controller/media.ts/WXAMPGetVideoList 接口为例进行说明。
// 媒资相关的控制器
@JsonController()
export class MediaController {
tokenService: TokenService;
validatorService: ValidatorService;
videoService: VideoService;

constructor() {
this.tokenService = Container.get(TokenService);
this.validatorService = Container.get(ValidatorService);
this.videoService = Container.get(VideoService);
}

/*
* 获取微信小程序视频列表
*/
@Post("/WXAMPGetVideoList")
public async wxampGetVideoList(@Body({ validate: false }) dto: GetVideoListDTO) {
let requestId = uuidv4();
let ctx = new ServiceContext(requestId);

try {
// 校验接口参数
await this.validatorService.Validate(ctx, dto);

// 获取视频列表
let condition = {
UserId: "",
Status: VideoStatus.PASS,
WechatMiniProgramStatus: VideoStatus.PASS,
Offset: dto.Offset,
Limit: dto.Limit,
};
let listVideoResult = await this.videoService.SearchVideo(ctx, condition);
return new Response(requestId, ErrorCode.OK, "OK", {
VideoList: listVideoResult.VideoList,
TotalCount: listVideoResult.TotalCount,
});
} catch (error) {
logger.error(ctx, `getVideoList error:`, error);
logger.info(ctx, `getVideoList dto:`, dto);
logger.error(ctx, `get video list fail: ${error.Code}, ${error.Message}, error:`, error);
return new Response(requestId, error.Code, error.Message, {});
}
}

// 其余代码省略...
}
MediaController 类通过装饰器(@JsonController)进行装饰,确保每个处理方法都能以 JSON 字符串返回,并且 HTTP Response 的头部 Content-Type 被设置为 application/json
MediaController 中定义了一个 wxampGetVideoList 方法,wxampGetVideoList 方法通过 @Post, 指定 /WXAMPGetVideoList 接口路由到此方法进行处理。
wxampGetVideoList 方法中定义了一个数据传输对象 GetVideoListDTO,并通过 @Body({ validate: false }) 装饰,此处将请求中的 HTTP Body 数据注入到 GetVideoListDTO 对象中。为了在校验非法的情况下使用自定义的回包,此处通过指定 validate: false 促使不在注入的同时进行参数校验,而是延迟到在 wxampGetVideoList 方法体中通过 Validate 方法进行显示校验。
wxampGetVideoList 方法体中分别调用了Service 服务类中的方法进行接口参数校验、获取视频列表。此处的Service 服务类通过使用 typedi 进行注入和管理。
wxampGetVideoList 方法返回 Response 对象, routing-controllers 将其转化为 JSON 字符串返回到请求客户端。

数据传输对象模块 src/dto

该模块主要封装了各个接口的请求参数, 并且通过 class-validator 实现参数校验,避免大量重复的if/else条件判断,提高代码可读性。下面将以 src/dto/media.tsGetVideoListDTO 为例进行说明。
// 获取视频列表的 DTO
export class GetVideoListDTO {
@IsOptional()
@Min(0, {
message: "Offset must be greater than or equals to 0",
context: {
errorCode: ErrorCode.ParamValueLegal,
},
})
Offset: number;

@IsOptional()
@Min(1, {
message: "Limit must be greater than 1",
context: {
errorCode: ErrorCode.ParamValueLegal,
},
})
@Max(100, {
message: "Limit must be lower than 100",
context: {
errorCode: ErrorCode.ParamValueLegal,
},
})
Limit: number;

constructor(offset: number, limit: number) {
this.Offset = offset;
this.Limit = limit;
}
}
GetVideoListDTO 类包含了 OffsetLimit 字段以及对应的校验条件(通过装饰器进行指定)。
对于 `Offset` 字段,通过 @Min 限制 Offset 的最短长度为 1,并且都定义了校验非法情况下的错误信息 message 和错误码 errorCode
如果违反校验条件,class-validator 将抛出 ValidationError 错误, ValidationError 的解析可以参考 ValidatorService 中的处理。
class-validator 提供了丰富校验条件,具体用法请参考官方文档。

实体模块 src/entity

该模块下封装了与数据库表一一对应的实体类。通过 typeorm 进行映射管理。
模块文件
描述
index.ts
用于导出实体类。
user.ts
定义了 User 实体类,与数据库中 User 表一一对应。
video.ts
定义了 Video 实体类,与数据库中 Video 表一一对应。
user_auth.ts
定义了 UserAuth 实体类,与数据库中 UserAuth 表一一对应。

服务模块 src/service

该模块主要封装了一些业务处理的逻辑,作为一个完整的子功能提供给 Controller 类使用。例如 Token 的生成、上传签名的生成、参数校验错误的解析以及数据库相关的操作等。下面以 src/service/video.ts 中的 SearchVideo 方法为例进行说明。
// 视频相关的服务类
@Service()
export class VideoService {
videoDao: VideoDao;

constructor() {
this.videoDao = Container.get(VideoDao);
}

// 搜索视频
public async SearchVideo(ctx: ServiceContext, condition: VideoListCondition) {
let videos = await this.videoDao.List(ctx, condition);
let totalCount = await this.videoDao.Count(ctx, condition);
let result: SearchVideoResult = {
VideoList: videos,
TotalCount: totalCount,
};
return result;
}
// 其余代码省略...
}
VideoService 类封装了与视频文件相关的业务处理方法,其中,SearchVideo 方法主要功能是根据搜索条件 condition 进行视频搜索。
VideoService 类使用 @Service 进行装饰,确保其可以被纳入 typedi 进行管理。
方法签名中有一个的 ServiceContext 上下文对象,后续可以根据业务需要增加一些 Service 类中需要用到的公共字段,避免了对全量的方法进行修改。
方法中在调用出错时或业务逻辑不符合预期时,会抛出一个 自定义错误类VodError,主要作用是区分不同错误返回给 Controller 类,进而返回给请求客户端。

数据访问模块 src/dao

该模块下主要封装了对于数据库的增删改查操作,用于返回业务逻辑需要的实体数据。例如根据条件获取视频列表,修改用户信息,查询用户信息,视频播放信息和用户信息聚合等相关操作。下面将以 src/dao/video.tsVideoDao 为例进行说明。
// 视频数据访问类
@Service()
export class VideoDao {
// 保存视频
public async Save(ctx: ServiceContext, video: Video) {
try {
const videoRepository: Repository<Video> = getManager().getRepository(Video);
let v = videoRepository.save(video);
logger.info(ctx, `video has been saved:`, v);
return v;
} catch (error) {
logger.error(ctx, `save video fail:`, error);
throw new VodError(ErrorCode.SaveVideoFail, "Fail to save video");
}
}
// 其余代码省略...
}
VideoDao 封装了对 Video 数据库进行的查询修改等操作,其中 Save 需要保存视频信息。

工具模块 src/util

该模块下定义了一些工具方法、错误码以及一些公共类(包括ResponseVodErrorContext等),您可根据自身业务特点进行扩充。