日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

作者 | 京東云開發(fā)者-京東零售 周明亮

原文鏈接:https://my.oschina.NET/u/4090830/blog/10116557

前言

玩歸玩,鬧歸鬧,別拿 C端 開玩笑!這里不推薦大家把 Node 服務(wù)作為 C 端服務(wù),畢竟它是單線程多任務(wù) 機(jī)制。這一特性是 JAVA 語言設(shè)計(jì)之初,就決定了它的使命 - Java >>>【】,這里就不多解釋了,大家去看看 Java 的歷史就知道啦~這也就決定了,它不能像后端語言那樣 多線程多任務(wù),用戶訪問量小還能承受,一旦承受訪問量大高并發(fā),就得涼涼~

那為什么我們還要去寫 Node 服務(wù)?主要是方便快捷,對于小項(xiàng)目可以迅速完成建設(shè),開發(fā)成本小。其次,主要通過寫 Nest 完成下面收獲:

  • 學(xué)習(xí)裝飾器語法,感受其簡潔優(yōu)美;
  • 自己學(xué)習(xí)一門新的開發(fā)框架,感受不同框架的優(yōu)缺點(diǎn),為以后開發(fā)選型打基礎(chǔ);
  • 感受服務(wù)端排查問題的復(fù)雜性,找找前端設(shè)計(jì)的靈感。

本篇文章主要是使用 NestJs + Sequelize + MySQL 完成基礎(chǔ)運(yùn)行, 帶大家了解 Node 服務(wù)端的基礎(chǔ)搭建,也可以順便看看 Java SpringBoot 項(xiàng)目的基礎(chǔ)結(jié)構(gòu),它倆真的非常相似,不信你去問服務(wù)端開發(fā)同學(xué)。

養(yǎng)成好習(xí)慣,看文章先一鍵三連~【點(diǎn)贊,關(guān)注,轉(zhuǎn)發(fā)】,評論可以看完再吐槽~繼續(xù)完善填坑~

第一步、項(xiàng)目跑起來

在選擇服務(wù)端的時(shí)候,我之前使用過 Egg.js ,所以這次就不選它了。其次,Egg 也是繼承了 Koa 的開發(fā)基礎(chǔ),加上 Express 也是基于 Koa 上創(chuàng)新的,兩者應(yīng)該差不多,就不選擇 Koa 和 Express 。

所以,我想嘗試下 Nest.js 看語法跟 Java 是一樣的,加上之前也自己開發(fā)過 Java + SpringBoot 的項(xiàng)目,當(dāng)然更古老的 SSH 2.0 也從無到有搭建過,即:Spring2.0 + Struts2+ Hibernate3.2,想想應(yīng)該會(huì)很容易上手,順便懷舊下寫寫。

參考文檔:

  • https://www.geeksforgeeks.org/best-nodejs-frameworks-for-App-development/?
  • ?https://anywhere.epam.com/business/best-node-js-frameworks?

說下我的想法,首先我們剛?cè)腴T,估計(jì)會(huì)有一堆不清楚的坑,我們先簡單點(diǎn),后續(xù)我們再繼續(xù)加深。既然要搞服務(wù)端,要搞就多搞點(diǎn),我們都去嘗鮮玩玩。我們打算使用 Nest 作為前端框架,Graphql 作為中間處理層。底層數(shù)據(jù)庫我們用傳統(tǒng)的 MySQL,比較穩(wěn)定可靠,而且相對比較熟悉,這個(gè)就不玩新的了,畢竟數(shù)據(jù)庫是一切的基石 。

說下我們具體實(shí)現(xiàn)步驟:

1.【必須】沒有任何數(shù)據(jù)庫,完成接口請求運(yùn)行,能夠跑起來;

2.【必須】創(chuàng)建基礎(chǔ)數(shù)據(jù)庫 MySQL ,接入 @nestjs/sequelize 庫 完成 增刪改查 功能即:CRUD

3.【可選】打算采取 Graphql 處理 API 查詢,做到精確數(shù)據(jù)查詢,這個(gè)已經(jīng)火了很多了,但是真正使用的很少,我們打算先感受下,后續(xù)可以直接用到業(yè)務(wù)。

4.【可選】接入 Swagger 自動(dòng)生成 API 文檔,快捷進(jìn)行前端與后端服務(wù)聯(lián)調(diào)測試。

?Swagger 是一個(gè)開源工具,用于設(shè)計(jì)、構(gòu)建、記錄和使用 RESTful web 服務(wù)。

5.【可選】接口請求,數(shù)據(jù)庫優(yōu)化處理

?請求分流,數(shù)據(jù)庫寫入加鎖,處理并發(fā)流程

?增加 middleware 中間件統(tǒng)一處理請求及響應(yīng),進(jìn)行鑒權(quán)處理,請求攔截等操作

?數(shù)據(jù)庫分割備份,數(shù)據(jù)庫融災(zāi)處理,分為:主、備、災(zāi)

?數(shù)據(jù)庫讀寫分離,數(shù)據(jù)雙寫,建立數(shù)據(jù)庫緩存機(jī)制,使用 redis 處理

也歡迎大家補(bǔ)充更多的優(yōu)化點(diǎn),我們一起探討~有興趣可以幫忙補(bǔ)充代碼哈~

確定了大概方向,我們就開始整。先不追求一步到位,否則越多越亂,錦上添花的東西,我們可以后續(xù)增加,基礎(chǔ)功能我們要優(yōu)先保障完成。Nest.js 官網(wǎng):https://docs.nestjs.com/ ,話不多說,我們直接開整。

# 進(jìn)入文件夾目錄

cdfull-stack-demo/packages

# 安裝腳手架

npmi -g @nestjs/cli

# 創(chuàng)建基礎(chǔ)項(xiàng)目

nestnew node-server-demo

# 進(jìn)入項(xiàng)目

cdnew node-server-demo

# 運(yùn)行項(xiàng)目測試

npmrun start:dev

我們移除一些不需要的東西,先簡單再復(fù)雜,別把自己搞暈了。接下來寫一個(gè)簡單示例感受下這個(gè)框架,之后完整的代碼,我會(huì)公布在后面。廢話不多說,開整!調(diào)整后目錄結(jié)構(gòu):

•common- 公用方法類

•config- 配置類文件

•controller- 控制器,用于處理前端發(fā)起的各類請求

•service- 服務(wù)類,用于處理與數(shù)據(jù)庫交互邏輯

•dto- DTO(Data Transfer Object)可以用于驗(yàn)證輸入數(shù)據(jù)、限制傳輸?shù)淖侄位蚋袷健?/p>

•entities- 實(shí)體類,用于描述對象相關(guān)的屬性信息

•module- 模塊,用于注冊所有的服務(wù)類、控制器類,類似 Spring 里面的 bean

?這里不能完全等同哈,兩個(gè)實(shí)現(xiàn)機(jī)制上就不同,只是幫助大家理解。

•mAIn.ts- nest 啟動(dòng)入口

•types- type 相關(guān)聲明類型

我在前端寫Java SpringBoot項(xiàng)目

只是寫 demo, 搞快點(diǎn)就沒有怎么寫注釋了,我感覺是一看就懂了,跟 Java SpringBoot 的寫法非常一致,部分代碼展示:

  • 控制器 controller
// packages/node-server-demo/src/controller/user/index.ts

import{Controller,Get,Query }from'@nestjs/common';

importUserServices from'@/service/user';

import{GetUserDto,GetUserInfoDto }from'@/dto/user';

@Controller('user')

exportclassUserController{

constructor(privatereadonlyuserService:UserServices){}

// Get 請求 user/name?name=bricechou

@Get('name')

asyncfindByName(@QuerygetUserDto:GetUserDto){

returnthis.userService.read.findByName(getUserDto.name);

}

// Get 請求 user/info?id=123

@Get('info')

asyncfindById(@QuerygetUserInfoDto:GetUserInfoDto){

constuser =awaitthis.userService.read.findById(getUserInfoDto.id);

return{gender:user.gender,job:user.job };

}

}

// packages/node-server-demo/src/controller/log/add.ts

import{Controller,Post,Body }from'@nestjs/common';

import{AddLogDto }from'@/dto/log';

importLogServices from'@/service/log';

@Controller('log')

exportclassCreateLogController{

constructor(privatereadonlylogServices:LogServices){}

// post('/log/add')

@Post('add')

create(@BodycreateLogDto:AddLogDto){

returnthis.logServices.create.create(createLogDto);

}

}

  • 數(shù)據(jù)轉(zhuǎn)換 Data Transfer Object
// packages/node-server-demo/src/dto/user.ts

exportclassCreateUserDto{

name:string;

age:number;

gender:string;

job:string;

}

// 可以分開寫,也可以合并

exportclassGetUserDto{

id?:number;

name:string;

}

// 可以分開寫,也可以合并

exportclassGetUserInfoDto{

id:number;

}

  • service 數(shù)據(jù)庫交互處理類
// packages/node-server-demo/src/service/user/read.ts

import{Injectable }from'@nestjs/common';

import{User }from'@/entities/User';

@Injectable

exportclassReadUserService{

constructor{}

asyncfindByName(name:string):Promise<User>{

// 可以處理判空,從數(shù)據(jù)庫讀取/寫入數(shù)據(jù),可能會(huì)被多個(gè) controller 進(jìn)行調(diào)用

console.info('ReadUserService findByName > ',name);

returnPromise.resolve({id:1,name,job:'程序員',gender:1,age:18});

}

asyncfindById(id:number):Promise<User>{

console.info('ReadUserService findById > ',id);

returnPromise.resolve({

id:1,

name:'BriceChou',

job:'程序員',

gender:1,

age:18,

});

}

}

  • module 模塊注冊,服務(wù)類 / 控制類
//packages/node-server-demo/src/module/user.ts

import{Module }from'@nestjs/common';

importUserService,{ReadUserService }from'@/service/user';

import{UserController }from'@/controller/user';

@Module({

providers:[UserService,ReadUserService],

controllers:[UserController],

})

exportclassUserModule{}

//packages/node-server-demo/src/module/index.ts 根模塊注入

import{Module }from'@nestjs/common';

import{UserModule }from'./user';

import{LogModule }from'./log';

@Module({

imports:[

UserModule,

LogModule,

],

})

exportclassAppModule{}

  • main.js 啟動(dòng)注冊的所有類
// packages/node-server-demo/src/main.ts

import{ AppModule } from'@/module';

import{ NestFactory } from'@nestjs/core';

import{ NestExpressApplication } from'@nestjs/platform-express';

asyncfunctionbootstrap{

constapp = awaitNestFactory.create<NestExpressApplication>(AppModule);

// 監(jiān)聽端口 3000

awaitapp.listen(3000);

}

bootstrap;

這樣一個(gè)單機(jī)的服務(wù)器就啟動(dòng)起來了,我們可以使用 Postwoman[https://hoppscotch.io/] 進(jìn)行請求,瞅瞅看返回效果。

我在前端寫Java SpringBoot項(xiàng)目

我在前端寫Java SpringBoot項(xiàng)目

控制臺(tái)也收到日志了,后面可以把這些日志請求保留成 .log 文件,這樣請求日志也有了,完美!下一步,我們開始連接數(shù)據(jù)庫,這樣就不用單機(jī)玩泥巴了~

第二步、配置 MySQL

MySQL 安裝其實(shí)很簡單,我電腦是 mac 的,所以下面的截圖都是以 mac 為例,先下載對應(yīng)的數(shù)據(jù)庫。

下載地址:https://dev.mysql.com/downloads/mysql/ 至于其他系統(tǒng)的,可以網(wǎng)上找教程,這個(gè)應(yīng)該爛大街了,我就不重復(fù)搬運(yùn)教程了。

  • 注意:安裝的數(shù)據(jù)庫,一定要設(shè)置密碼,連接數(shù)據(jù)庫必須要有密碼,否則會(huì)導(dǎo)致連接數(shù)據(jù)庫失敗。
  • MySQL 我們只安裝數(shù)據(jù)庫就行,熟悉指令的童鞋,就直接命令行操作就行。
  • 不熟悉的話,那就下載圖形化管理工具。

?Mysql 官方控制臺(tái) https://dev.mysql.com/downloads/workbench/?

?windows 也可以使用 https://www.heidisql.com/download.php?download=installer?

PS:安裝 workbench 時(shí)發(fā)現(xiàn)要求 MacOS 13以上,我的電腦是 MacOS 12。

白白下載,所以只能 https://downloads.mysql.com/archives/workbench/ 從歸檔里面找低版本 8.0.31。對于數(shù)據(jù)庫服務(wù)也有版本要求,大家按照自己電腦版本,選擇支持的版本即可。 https://downloads.mysql.com/archives/community/。我這邊選擇的是默認(rèn)最新版本:8.0.34,下載好直接安裝,一路 Next 到底,記住自己輸入的 Root 密碼!!!

確認(rèn)好當(dāng)前數(shù)據(jù)庫是否已經(jīng)運(yùn)行起來了,啟動(dòng) Workbench 查看狀態(tài)。

我在前端寫Java SpringBoot項(xiàng)目

??1.創(chuàng)建數(shù)據(jù)庫

我在前端寫Java SpringBoot項(xiàng)目

??數(shù)據(jù)庫存在字符集選擇,不同的字符集和校驗(yàn)規(guī)則,會(huì)對存儲(chǔ)數(shù)據(jù)產(chǎn)生影響,所以大家可以自行查詢,按照自己存儲(chǔ)數(shù)據(jù)原則選擇,我這里默認(rèn)選最廣泛的。確認(rèn)好,就選擇右下角的應(yīng)用按鈕。

2.創(chuàng)建表和屬性

我在前端寫Java SpringBoot項(xiàng)目

??選項(xiàng)解答:

•PRIMARY KEY是表中的一個(gè)或多個(gè)列的組合,它用于唯一標(biāo)識表中的每一行。

•Not NULL和 Unique就不解釋,就是直譯的那個(gè)意思。

•GENERATED生成列是表中的一種特殊類型的列,它的值不是從插入語句中獲取的,而是根據(jù)其他列的值通過一個(gè)表達(dá)式或函數(shù)生成的。

CREATETABLEpeople (

first_name VARCHAR(100),

last_name VARCHAR(100),

full_name VARCHAR(200)AS(CONCAT(first_name,' ',last_name))

);

  • UNSIGNED 這個(gè)數(shù)值類型就只能存儲(chǔ)正數(shù)(包括零),不會(huì)存儲(chǔ)負(fù)數(shù)。
  • ZEROFILL 將數(shù)值類型的字段的前面填充零,他會(huì)自動(dòng)使字段變?yōu)?UNSIGNED,直到該字段達(dá)到聲明的長度,如:00007
  • BINARY 用于存儲(chǔ)二進(jìn)制字符串,如聲明一個(gè)字段為 BINARY (5),那么存儲(chǔ)在這個(gè)字段中的字符串都將被處理為長度為 5 的二進(jìn)制字符串。

?如嘗試存儲(chǔ)一個(gè)長度為 3 的字符串,那么它將在右側(cè)用兩個(gè)空字節(jié)填充。

?如果你嘗試存儲(chǔ)一個(gè)長度為 6 的字符串,那么它將被截?cái)酁殚L度為 5

?主要用途是存儲(chǔ)那些需要按字節(jié)進(jìn)行比較的數(shù)據(jù),例如加密哈希值

  • 此外也可順手傳創(chuàng)建一個(gè)索引,方便快速查找。
CREATETABLE`rrweb`.`test_sys_req_log`(

`id`INTUNSIGNEDNOTNULLAUTO_INCREMENT,

`content`TEXTNOTNULL,

`l_level`INTUNSIGNEDNOTNULL,

`l_category`VARCHAR(255)NOTNULL,

`l_created_at`TIMESTAMPNOTNULLDEFAULTCURRENT_TIMESTAMP,

`l_updated_at`TIMESTAMPNOTNULLDEFAULTCURRENT_TIMESTAMP,

PRIMARYKEY(`id`),

UNIQUEINDEX`id_UNIQUE`(`id`ASC)VISIBLE,

INDEX`table_index`(`l_level`ASC,`l_category`ASC,`l_time`ASC)VISIBLE);

3.連接數(shù)據(jù)庫

由于目前 node-oracledb 官方尚未提供針對 Apple Silicon 架構(gòu)的預(yù)編譯二進(jìn)制文件。導(dǎo)致我們無法在 Mac M1 芯片上使用 TypeORM 鏈接數(shù)據(jù)庫操作,它目前只支持 Mac x86 芯片。哎~折騰老半天,查閱各種文檔,居然有這個(gè)坑,沒關(guān)系我們換個(gè)方式打開。

我們不得不放棄,從而選用 https://docs.nestjs.com/techniques/database#sequelize-integration 哐哐哐~一頓操作猛如虎,盤它!

  • 安裝 Sequelize
# 安裝連接庫

npminstall --save @nestjs/sequelize sequelize sequelize-type mysql2

# 安裝 type

npminstall --save-dev @types/sequelize

  • 配置數(shù)據(jù)庫基礎(chǔ)信息
// packages/node-server-demo/src/module/index.ts

import{Module }from'@nestjs/common';

import{UserModule }from'./user';

import{LogModule }from'./log';

import{Log }from'@/entities/Log';

import{SequelizeModule }from'@nestjs/sequelize';

@Module({

imports:[

SequelizeModule.forRoot({

dialect:'mysql',

// 按數(shù)據(jù)庫實(shí)際配置

host:'127.0.0.1',

// 按數(shù)據(jù)庫實(shí)際配置

port:3306,

// 按數(shù)據(jù)庫實(shí)際配置

username:'root',

// 按數(shù)據(jù)庫實(shí)際配置

password:'hello',

// 按數(shù)據(jù)庫實(shí)際配置

database:'world',

synchronize:true,

models:[Log],

autoLoadModels:true,

}),

LogModule,

UserModule,

],

})

exportclassAppModule{}

  • 實(shí)體與數(shù)據(jù)庫一一映射處理
import{getNow }from'@/common/date';

import{

Model,

Table,

Column,

PrimaryKey,

DataType,

}from'sequelize-type';

@Table({tableName:'test_sys_req_log'})

exportclassLogextendsModel<Log>{

@PrimaryKey

@Column({

type:DataType.INTEGER,

autoIncrement:true,

field:'id',

})

id:number;

@Column({field:'content',type:DataType.TEXT})

content:string;

@Column({field:'l_level',type:DataType.INTEGER})

level:number;// 3嚴(yán)重,2危險(xiǎn),1輕微

@Column({field:'l_category'})

category:string;// 模塊分類/來源分類

@Column({

field:'l_created_at',

type:DataType.NOW,

defaultValue:getNow,

})

createdAt:number;

@Column({

field:'l_updated_at',

type:DataType.NOW,

defaultValue:getNow,

})

updatedAt:number;

}

  • module 注冊實(shí)體
//packages/node-server-demo/src/module/log.ts

import{Module }from'@nestjs/common';

import{SequelizeModule }from'@nestjs/sequelize';

import{Log }from'@/entities/Log';

importLogServices,{

CreateLogService,

UpdateLogService,

DeleteLogService,

ReadLogService,

}from'@/service/log';

import{

CreateLogController,

RemoveLogController,

UpdateLogController,

}from'@/controller/log';

@Module({

imports:[SequelizeModule.forFeature([Log])],

providers:[

LogServices,

CreateLogService,

UpdateLogService,

DeleteLogService,

ReadLogService,

],

controllers:[CreateLogController,RemoveLogController,UpdateLogController],

})

exportclassLogModule{}

  • service 操作數(shù)據(jù)庫處理數(shù)據(jù)
import{Log }from'@/entities/Log';

import{Injectable }from'@nestjs/common';

import{AddLogDto }from'@/dto/log';

import{InjectModel }from'@nestjs/sequelize';

import{ResponseStatus }from'@/types/BaseResponse';

import{getErrRes,getSucVoidRes }from'@/common/response';

@Injectable

exportclassCreateLogService{

constructor(

@InjectModel(Log)

privatelogModel:typeofLog,

){}

asynccreate(createLogDto:AddLogDto):Promise<ResponseStatus<null>>{

console.info('CreateLogService create > ',createLogDto);

const{level =1,content ='',category ='INFO'}=createLogDto ||{};

conststr =content.trim;

if(!str){

returngetErrRes(500,'日志內(nèi)容為空');

}

constitem ={

level,

category,

// Tips: 為防止外部數(shù)據(jù)進(jìn)行數(shù)據(jù)注入,我們可以對內(nèi)容進(jìn)行 encode 處理。

// content: encodeURIComponent(str),

content:str,

};

awaitthis.logModel.create(item);

returngetSucVoidRes;

}

}

一路操作猛如虎,回頭一看嘿嘿嘿~終于,我們收到了來自外界的第一條數(shù)據(jù)! hello world!

我在前端寫Java SpringBoot項(xiàng)目

我在前端寫Java SpringBoot項(xiàng)目

??連接及創(chuàng)建數(shù)據(jù)成功!此時(shí)已經(jīng)完成基礎(chǔ)功能啦~

第三步、實(shí)現(xiàn) CRUD 基礎(chǔ)功能

剩下的內(nèi)容,其實(shí)大家可以自行腦補(bǔ)了,就是調(diào)用數(shù)據(jù)庫的操作邏輯。先說說什么是 CRUD

  • C create 創(chuàng)建
  • R read 讀取
  • U update 更新
  • D delete 刪除

下面給個(gè)簡單示例,大家看看,剩下就去找文檔,實(shí)現(xiàn)業(yè)務(wù)邏輯即可:

import{Injectable }from'@nestjs/common';

import{InjectModel }from'@nestjs/sequelize';

import{User }from'./user.model';

@Injectable

exportclassUserService{

constructor(

@InjectModel(User)

privateuserModel:typeofUser,

){}

// 創(chuàng)建新數(shù)據(jù)

asynccreate(user:User){

constnewUser =awaitthis.userModel.create(user);

returnnewUser;

}

// 查找所有數(shù)據(jù)

asyncfindAll{

returnthis.userModel.findAll;

}

// 按要求查找單個(gè)

asyncfindOne(id:string){

returnthis.userModel.findOne({where:{id }});

}

// 按要求更新

asyncupdate(id:string,user:User){

awaitthis.userModel.update(user,{where:{id }});

returnthis.userModel.findOne({where:{id }});

}

// 按要求刪除

asyncdelete(id:string){

constuser =awaitthis.userModel.findOne({where:{id }});

awaituser.destroy;

}

}

Tips: 進(jìn)行刪除的時(shí)候,我們可以進(jìn)行假刪除,兩個(gè)數(shù)據(jù)庫,一個(gè)是備份數(shù)據(jù)庫,一個(gè)是主數(shù)據(jù)庫。主數(shù)據(jù)庫可以直接刪除或者增加標(biāo)識表示刪除。備份數(shù)據(jù)庫,可以不用刪除只寫入和更新操作,這樣可以進(jìn)行數(shù)據(jù)還原操作。

此外,為了防止 SQL 數(shù)據(jù)庫注入,大家需要對數(shù)據(jù)來源進(jìn)行統(tǒng)一校驗(yàn)處理或者直接進(jìn)行 encode 處理,對于重要數(shù)據(jù)可以直接進(jìn)行 MD5 加密處理,防止數(shù)據(jù)庫被直接下載泄露。關(guān)于 SQL 數(shù)據(jù)庫的安全處理,網(wǎng)上教程有很多,大家找一找就可以啦~

部署就比較簡單了,我們就不需要一一贅述了,數(shù)據(jù)庫可以用集團(tuán)提供的云數(shù)據(jù)庫,而 Nest 就是普通的 node 部署。

分享到:
標(biāo)簽:SpringBoot
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定