【翻譯】Yii2第2章用Yii2創(chuàng)建自定義應(yīng)用(第1部分)

在這一章里,我們將看到Y(jié)ii2怎樣幫助我們創(chuàng)建web應(yīng)用。示例雖然很簡(jiǎn)單,但整個(gè)過(guò)程都符合軟件工程思想。我們將完成應(yīng)用開發(fā)的每一個(gè)步驟,并且每一步都會(huì)根據(jù)權(quán)威書籍中的實(shí)踐來(lái)進(jìn)行:

北京網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)建站!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、成都響應(yīng)式網(wǎng)站建設(shè)公司等網(wǎng)站項(xiàng)目制作,到程序開發(fā),運(yùn)營(yíng)維護(hù)。創(chuàng)新互聯(lián)建站于2013年創(chuàng)立到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)建站

創(chuàng)建領(lǐng)域模型:這本書解釋了領(lǐng)域驅(qū)動(dòng),Tackling Complexity in the Heart of Software, Eric Evans, Addison-Wesley Professional

設(shè)置測(cè)試裝置:我們遵照驗(yàn)收測(cè)試驅(qū)動(dòng)實(shí)踐,Growing Object-oriented Software, Guided by Tests, Steve Freeman and Nat Pryce, Addison-Wesley Professional

設(shè)置開發(fā)流水線

持續(xù)交付:Reliable Software Releases through Build, Test, and Deployment Automation, Jez Humble and David Farley, Addison-Wesley Professional

持續(xù)集成:Improving Software Quality and Reducing Risk, Paul M. Duvall, Steve Matyas, and Andrew Glover, Addison-Wesley Professional

紅-綠-重構(gòu) 開發(fā)循環(huán):深度解釋,請(qǐng)參考下列圖書:

Clean Code:A Handbook of Agile Software Craftsmanship, Robert Martin, Prentice Hall

Test-Driven Development by Example, Kent Beck, Addison-Wesley Professional

部署和手工測(cè)試:這符合持續(xù)交付,并且這些步驟也是必不可少的

保持專注。

設(shè)計(jì)階段

貫穿整本書,在使用示例應(yīng)用的時(shí)候,我們需要注意實(shí)際需求。在這個(gè)小節(jié),我們將定義整個(gè)示例的場(chǎng)景。

任務(wù)

假設(shè)我們有一個(gè)小的商業(yè)應(yīng)用,要對(duì)外提供一些服務(wù)。我們有一些客戶,他們有一些數(shù)目巨大的賬目記錄在紙面上,用商業(yè)卡片管理非常不方便。因此,我們需要用自動(dòng)化的方式把這些檔案管理起來(lái)。

首先,我們需要一些增刪查改(CRUD)界面進(jìn)行記錄管理,為客戶展示最核心的屬性。

很明顯,我們的業(yè)務(wù)和客戶可能會(huì)隨著時(shí)間的推移而增長(zhǎng)、變化,因此我們的應(yīng)用也應(yīng)該隨之變化。在一開始,我們就應(yīng)該為可能的變化做好準(zhǔn)備。

本著吃自己狗食的原則(譯注:微軟在1998年提出),既然自己開發(fā)的系統(tǒng)自己要使用,那這個(gè)系統(tǒng)最好保證是高質(zhì)量的。

領(lǐng)域模型設(shè)計(jì)

很明顯,我們將在應(yīng)用中處理客戶模型。在“customer”和“client”兩個(gè)詞中,我們覺得“customer”更為貼切。

一個(gè)客戶(customer)是一個(gè)人,他至少具有姓名、地址、電子郵件,以及電話號(hào)碼等屬性。我們?yōu)榭蛻籼峁┮粋€(gè)服務(wù),按小時(shí)統(tǒng)計(jì),并根據(jù)合約支付這段時(shí)間產(chǎn)生的費(fèi)用。這就是我們?cè)诘谝淮蔚O(shè)計(jì)中打算解決的問(wèn)題。

我們假設(shè)每位客戶都是單個(gè)的人,因此我們不用處理公司,有多個(gè)聯(lián)系人的情況。姓名是一個(gè)復(fù)雜的結(jié)構(gòu),如果我們深入細(xì)節(jié),有敬語(yǔ)、職務(wù)、昵稱、中間名、姓等屬性需要考慮。但在這個(gè)應(yīng)用中,我們真正感興趣的并不是客戶的姓名,我們只是需要用姓名來(lái)識(shí)別一個(gè)客戶。因此,我們將簡(jiǎn)單的使用一個(gè)文本行來(lái)表示,允許我們按任何格式來(lái)寫入姓名。地址同樣可以是一個(gè)復(fù)雜的結(jié)構(gòu),這次我們打算用一個(gè)結(jié)構(gòu)來(lái)描述,而不再是一個(gè)簡(jiǎn)單的文本行。這是因?yàn)槲覀冃枰ㄟ^(guò)地址來(lái)實(shí)現(xiàn)以下兩件事情。

進(jìn)行一些統(tǒng)計(jì),例如在一個(gè)特定的城市,有多少個(gè)客戶

遵照不同的文化背景,正確地生成郵寄地址

因此,我們決定采用下面的結(jié)構(gòu):

用途(例如:賬單地址、購(gòu)物地址、家庭地址、工作地址)

國(guó)家

州,國(guó)家下級(jí)的區(qū)域,比如美國(guó)

城市

街道

建筑物

部門/辦公室

收件人姓名

郵政編碼

我們應(yīng)該注意到,一個(gè)地址能代表一個(gè)部門、郵箱、辦公室、組織中的雇員,甚至是整個(gè)建筑。同樣,一個(gè)客戶也可以多個(gè)地址。

電話這個(gè)實(shí)體具有以下屬性:

用途(個(gè)人或工作)

號(hào)碼

一個(gè)客戶可能有幾個(gè)電話號(hào)碼,通過(guò)用途字段區(qū)分。

除了姓名、地址、電話這個(gè)實(shí)體之外,我們的職員需要通過(guò)一種途徑對(duì)客戶進(jìn)行自由的描述。這里我們簡(jiǎn)化了姓名屬性。然后,我們加入生日、電子郵件屬性,當(dāng)然,一個(gè)客戶可以有多個(gè)電子郵件。

我們先停一下。

我們現(xiàn)在能畫出客戶模型的完整聚合圖了,如下圖所示:

根據(jù)Eric Evans的《領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》,客戶是一個(gè)實(shí)體(Entity),也就是說(shuō),是一個(gè)狀態(tài)可以改變的對(duì)象,因此我們要關(guān)心它在整個(gè)系統(tǒng)中的一致性。而其它部分是值對(duì)象(Value Object),意味著初始創(chuàng)建后,狀態(tài)不會(huì)改變的對(duì)象,因此他們是可以完全互換的。

為了簡(jiǎn)化處理,我們不再詳細(xì)描述商業(yè)上是如何處理客戶的,我們不打算在這本書中涵蓋它。無(wú)論如何,讓我們把注意力回到我們?yōu)榭蛻籼峁┑囊幌盗蟹?wù)中來(lái),維護(hù)這些記錄將會(huì)很有用。我們將在后面的章節(jié)用到這個(gè)模型。

目標(biāo)特性

讓我們來(lái)執(zhí)行一個(gè)特定的任務(wù)??紤]到有的人給我們打電話(假如我們已經(jīng)識(shí)別出號(hào)碼),我們想獲取呼入者的所有詳細(xì)信息。在應(yīng)用中,如果這個(gè)號(hào)碼沒(méi)有找到關(guān)聯(lián)的人,那我們就知道他并不是我們的客戶。如果找到關(guān)聯(lián)人,我們至少可以直接用他的姓名跟他打招呼,這是很好的客戶服務(wù)。

我們應(yīng)該理解數(shù)據(jù)庫(kù)查詢,我們需要一個(gè)途徑可以插入數(shù)據(jù),有可能還需要編輯和刪除它。因此,我們第一次開發(fā)迭代的特性包含以下內(nèi)容:

將客戶信息插入數(shù)據(jù)庫(kù)

在數(shù)據(jù)庫(kù)中編輯客戶信息

從數(shù)據(jù)庫(kù)中刪除客戶信息

根據(jù)電話號(hào)碼從數(shù)據(jù)庫(kù)中查詢客戶信息

構(gòu)造通用的數(shù)據(jù)庫(kù)查詢并不是我們的目標(biāo),我們僅僅需要根據(jù)一個(gè)電話號(hào)碼進(jìn)行查詢。

讓我們開始吧。

初始準(zhǔn)備

一直到本書結(jié)束,我們將在接下來(lái)的章節(jié)中討論同一個(gè)應(yīng)用,因此準(zhǔn)備工作只需要做這一次。

下載示例代碼:Packt的網(wǎng)站上可以下載你購(gòu)買過(guò)圖書的示例代碼,地址是http://www.packtpub.com,如果你已經(jīng)購(gòu)買了這本書,請(qǐng)?jiān)L問(wèn)http://www.packtpub.com/support,注冊(cè)后會(huì)直接將文件通過(guò)電子郵件發(fā)送給你。

配置項(xiàng)目管理

我們要開發(fā)的應(yīng)用,從本質(zhì)上說(shuō),是一個(gè)客戶關(guān)系管理系統(tǒng)(CRM)。因此,我們首先創(chuàng)建一個(gè)名為 crmapp 的目錄。

請(qǐng)注意,正本書中,通過(guò)命令行調(diào)用的示例,都假定你當(dāng)前目錄為crmapp目錄。

Yii2推薦使用包管理器Composer進(jìn)行安裝,因此我們就來(lái)使用這個(gè)工具。你可以去閱讀Composer的完整文檔了解詳細(xì)的細(xì)節(jié),我們?cè)谶@里準(zhǔn)備了一個(gè)簡(jiǎn)短的說(shuō)明:

所有通過(guò)Composer安裝的包,都會(huì)存放在項(xiàng)目路徑下,一個(gè)名為vendor的子目錄中。

與Composer相關(guān)的數(shù)據(jù),所有依賴和其它信息,都保存在名為composer.json的清單文件中,位于項(xiàng)目根目錄下。只要你在這個(gè)文件中申明了依賴,你就能在任何時(shí)候安全的刪除vendor目錄,并在調(diào)用php composer.phar install 或 php composer.phar update時(shí)完全重建。

Composer的文檔描述了一個(gè)獲取composer.phar的方法:

curl-sShttps://getcomposer.org/installer|php

當(dāng)然,如果你的PATH路徑中如果沒(méi)有CURL,你也可以直接去Composer的官方網(wǎng)站https://getcomposer.org/ 直接下載PHAR文件。(譯注:如果是windows環(huán)境,推薦直接下載一個(gè)Composer的安裝包,安裝完成后,添加到PATH目錄,以后就可以直接使用composer <command>進(jìn)行調(diào)用,而不使用php composer.phar <command>,更為方便)。

我們準(zhǔn)備好后,就可以按下面的格式執(zhí)行命令了:

phpcomposer.phar<command>

假定你會(huì)使用版本控制系統(tǒng)來(lái)管理代碼,本書的代碼使用Git(http://git-scm.com/)進(jìn)行管理。

準(zhǔn)備階段快速指引:

mkdircrmapp cdcrmapp curl-sS|php gitinit 配置測(cè)試工具

正如我們?cè)诒菊碌拈_始部分所說(shuō),我們將遵從測(cè)試優(yōu)先的開發(fā)實(shí)踐來(lái)進(jìn)行驗(yàn)收測(cè)試。這樣做的原因如下:

我們想檢查應(yīng)用是否能正常工作,又不想使用乏味的人工測(cè)試

我們還沒(méi)有深度的單元測(cè)試需求,因?yàn)槲覀兡壳爸饕墓ぷ髦皇前岩呀?jīng)存在的組件裝配在一起,因此,通過(guò)對(duì)UI進(jìn)行端對(duì)端的驗(yàn)收測(cè)試最為簡(jiǎn)單可行

如果我們關(guān)心用戶特性請(qǐng)求的實(shí)現(xiàn)情況,我們需要一些形式的驗(yàn)收測(cè)試。

Yii2內(nèi)置支持Codeception測(cè)試框架,官方站點(diǎn)是 http://codeception.com/。我們不會(huì)在本身中直接使用它,但是 yii2-codeception(https://github.com/yiisoft/yii2-codeception)提供了一些輔助類,來(lái)集成到Y(jié)ii框架中。

讓我們來(lái)申明,我們需要在項(xiàng)目中使用 Codeception,執(zhí)行下面的命令:

phpcomposer.pharrequire"codeception/codeception:*"

稍等片刻,直到Composer執(zhí)行完成。

目前,composer.json文件的內(nèi)容是:

{ "require":{ "codeception/codeception":"*", } }

命令 php composer.phar require <包名:版本> 只是一個(gè)輔助方法,將require塊插入到清單文件中,并調(diào)用update命令。

當(dāng)然,我也需要將Yii2同樣作為依賴加入,但在這之前,讓我們先干一件事情。

正如我們看到的,Codeception已經(jīng)存在于 ./vendor/bin/codecept 目錄中了。這個(gè)路徑敲起來(lái)比較長(zhǎng),在POSIX兼容的shell中,比如bash,允許我們使用下面的方式來(lái)進(jìn)行簡(jiǎn)化:

aliascept="./vender/bin/codecept"

這樣做更好。在本章余下的部分,我們都假定你已經(jīng)執(zhí)行了上面這條命令。

Codeception是一個(gè)復(fù)雜的系統(tǒng),所以我們需要依賴它自己內(nèi)建的命令。沒(méi)必要深入Codeception的內(nèi)部細(xì)節(jié),我們只是簡(jiǎn)單實(shí)用就可以了。執(zhí)行下面的命令:

ceptbootstrap

這將為Codeception生成一個(gè)tests目錄,并進(jìn)行配置。

現(xiàn)在,讓我們創(chuàng)建一個(gè)傻瓜型的驗(yàn)收測(cè)試,用以檢查我們的測(cè)試工具。

ceptgenerate:ceptacceptanceSmokeTest

這個(gè)命令將生成 SmokeTestCept.php,位于 tests/acceptance 目錄下。當(dāng)我們打開這個(gè)文件,我們將看到如下代碼(根據(jù)Codeception版本,代碼可能略有不同):

$I=newAcceptanceTester($scenario); $I->wantTo(\'performactionsandseeresult\');

AcceptanceTester是一個(gè)可以模仿瀏覽器后的真實(shí)用戶,對(duì)應(yīng)用進(jìn)行測(cè)試的類。Codeception同時(shí)也提供 CodeGuy 用以進(jìn)行單元測(cè)試,提供 TestGuy 進(jìn)行功能測(cè)試,在后面我們才會(huì)用到。

當(dāng)我們調(diào)用 AcceptanceTester.wantTo("do something")時(shí),我們只是為下面的測(cè)試行為創(chuàng)建了一個(gè)標(biāo)題(用雙引號(hào)括起來(lái)的)。

讓我們修改一下代碼,加入冒煙測(cè)試的功能,對(duì)我們的首頁(yè)進(jìn)行測(cè)試:

$I=newAcceptanceTester($scenario); $I->wantTo(\'Seethatlandingpageisup\'); $I->amOnPage(\'/\'); $I->see(\'OurCRM\');

當(dāng)我們?cè)L問(wèn)應(yīng)用首頁(yè)的時(shí)候,我們希望看到有 Our CRM 這一行。假設(shè)我們應(yīng)用中已經(jīng)有那么一個(gè)標(biāo)題存在了。

現(xiàn)在運(yùn)行測(cè)試:

ceptrun

我們會(huì)看到失敗的信息,因?yàn)槲覀冞€沒(méi)有設(shè)置web服務(wù)器,處理 / 請(qǐng)求。這樣,到了該我們寫一些生產(chǎn)代碼來(lái)通過(guò)這個(gè)測(cè)試的時(shí)候了。然而,到目前而言,我們需要的還不是生產(chǎn)代碼,我們的基礎(chǔ)服務(wù)都還沒(méi)有建立起來(lái)。我們需要先建立發(fā)布機(jī)制。

配置發(fā)布流水線

我們已經(jīng)說(shuō)過(guò),編寫的web驗(yàn)收測(cè)試會(huì)模擬真實(shí)用戶,在瀏覽器中打開應(yīng)用,通過(guò)可視的UI進(jìn)行交互。因此,我們現(xiàn)在需要做的是將應(yīng)用整個(gè)部署到我們能運(yùn)行驗(yàn)收測(cè)試的機(jī)器。

提示:最常見的情況是,你決定開發(fā)和測(cè)試使用同一臺(tái)機(jī)器,這是錯(cuò)誤的!別這么干。

很可能你的工作平臺(tái)和應(yīng)用最終要運(yùn)行的機(jī)器不是一樣的。參照已有數(shù)十年歷史的工業(yè)生產(chǎn),這已經(jīng)是一個(gè)持續(xù)不斷的問(wèn)題了。當(dāng)應(yīng)用的生命周期預(yù)計(jì)是數(shù)年時(shí),在不同環(huán)境的生產(chǎn)服務(wù)器上測(cè)試你的應(yīng)用,你會(huì)面臨相似的集成問(wèn)題。當(dāng)然,這不是將打包好的軟件賣給用戶,這還是要簡(jiǎn)便一些。在我們的案例中,我們假定一個(gè)單一的發(fā)布點(diǎn)只有一個(gè)固定web應(yīng)用,因此,簡(jiǎn)便性不是問(wèn)題,可重復(fù)性測(cè)試才是問(wèn)題。

最終,你的驗(yàn)收測(cè)試將會(huì)包含以下幾個(gè)步驟:

將應(yīng)用發(fā)布到測(cè)試服務(wù)器

在你的機(jī)器上運(yùn)行驗(yàn)收測(cè)試

當(dāng)然,你可以在測(cè)試服務(wù)器上運(yùn)行驗(yàn)收測(cè)試。要這樣做,你只需要用localhost這個(gè)本地回路網(wǎng)絡(luò)接口來(lái)配置測(cè)試就可以了。然而,還是需要你安裝一些與測(cè)試服務(wù)器不相干的軟件。例如,如果你想全棧運(yùn)行,使用Selenium進(jìn)行瀏覽器內(nèi)測(cè)試,你可能需要安裝一個(gè)web瀏覽器,Java運(yùn)行時(shí),虛擬幀緩沖軟件,并且這又需要安裝它們各自相關(guān)的軟件,這樣做非常費(fèi)勁。最有效的做法是使用你自己的桌面環(huán)境,來(lái)運(yùn)行web驗(yàn)收測(cè)試。

提示:這當(dāng)然不是在談?wù)搯卧獪y(cè)試和功能測(cè)試。單元測(cè)試由于只與本身有關(guān),應(yīng)在有原始代碼的地方執(zhí)行,完全不需要部署。功能測(cè)試,應(yīng)在部署后的應(yīng)用上測(cè)試,因?yàn)樾枰獪y(cè)試經(jīng)過(guò)配置后的最終應(yīng)用以及交互的正確性。

在任何案例中,理想化的方案是,你只需一個(gè)就像deploy這樣的簡(jiǎn)單命令,就能完成以下功能:

訪問(wèn)并啟動(dòng)目標(biāo)機(jī)器(特別是,當(dāng)它是一個(gè)虛擬機(jī)實(shí)例的時(shí)候)

確保除應(yīng)用外,環(huán)境是有效的

將當(dāng)前代碼拷貝到目標(biāo)機(jī)器

在目標(biāo)機(jī)器上,配置剛拷貝過(guò)去的代碼的環(huán)境

啟動(dòng)應(yīng)用

你應(yīng)該能在命令行中輸入deploy,并敲擊Enter鍵,完成上述的所有步驟。正如Martin Fowler在他的《持續(xù)集成》(http://martinfowler.com/articles/continuousIntegration.html)中所說(shuō),這對(duì)你來(lái)說(shuō)小菜一碟。理想情況下,部署行為應(yīng)該在你啟動(dòng)驗(yàn)收測(cè)試工具時(shí)自動(dòng)完成。

在本書中,我們只關(guān)心最后兩步。因?yàn)槲覀冮_發(fā)的是PHP應(yīng)用,只要目標(biāo)機(jī)器上的web服務(wù)器在運(yùn)行,”啟動(dòng)應(yīng)用“這一步就算已經(jīng)完成了。

本書僅關(guān)注web應(yīng)用開發(fā),并不涉及系統(tǒng)管理,那是系統(tǒng)管理員的事。然而,在附錄A,”使用Vagrant進(jìn)行部署設(shè)置“,我們準(zhǔn)備介紹一個(gè)基于虛擬機(jī)的部署,同樣也很容易在任何桌面工作站上實(shí)現(xiàn)。你可以不必需要另外一臺(tái)物理機(jī),就仍然能模擬現(xiàn)實(shí)世界的部署過(guò)程。如果你別無(wú)選擇,強(qiáng)烈推薦你讀讀。實(shí)際上,采用那里的描述,本身所有的代碼都準(zhǔn)備好了。讓我們假設(shè)你有一個(gè)準(zhǔn)備好的環(huán)境和deploy命令,為了簡(jiǎn)化,我們同時(shí)假定每次運(yùn)行驗(yàn)收測(cè)試前,部署都會(huì)自動(dòng)運(yùn)行。部署的結(jié)果可以從你的機(jī)器通過(guò)一個(gè)簡(jiǎn)單的URL進(jìn)行訪問(wèn),驗(yàn)收測(cè)試工具會(huì)將它作為應(yīng)用的入口點(diǎn)。

現(xiàn)在,讓我們到Codeception的跟驗(yàn)收測(cè)試相關(guān)的配置部分,打開文件 tests/acceptance.suite.yml,把入口URL加入到 modules.config.PhpBrowser.url 詞條中。假定你沒(méi)修改過(guò)這個(gè)文件,文件內(nèi)容看起來(lái)應(yīng)該像這樣:

class_name:AcceptanceTester modules: enabled: -PhpBrowser -WebHelper config: PhpBrowser: url:\'http://YOUR.APPLICATION.URL\'

(譯注:本機(jī)acceptance.suite.yml文件格式跟上面不同,不存在config項(xiàng),url直接放在enabled的PhpBrowser下)

舉例來(lái)說(shuō),如果你用Apache的基于IP的虛擬主機(jī)技術(shù)來(lái)配置目標(biāo)機(jī)器(https://httpd.apache.org/docs/2.2/vhosts/ip-based.html),modules.config.PhpBrowser.url 的值就應(yīng)該像這樣:http://127.0.0.01:8000。

當(dāng)我們改變配置,我們需要重建Codeception,執(zhí)行下面的命令:

ceptbuild

不要忘記 cept 這個(gè)別名是我們自己創(chuàng)建的。實(shí)際運(yùn)行的是 ./vendor/bin/codecept 文件。

如果你現(xiàn)在運(yùn)行測(cè)試:

ceptrun

你應(yīng)該可以看到如下輸出:

你會(huì)看到Codeception在 / 路由上顯示了一些東西,但還不是我們期望的。根據(jù)使用的Apache版本不同,可以是404錯(cuò)誤或者403錯(cuò)誤。如果你使用的其它Web服務(wù)器,可能顯示的另外的錯(cuò)誤信息。無(wú)論如何,問(wèn)題的根源很簡(jiǎn)單,這就是我們需要在外界可訪問(wèn)的web目錄中,加入index.php文件。

創(chuàng)建一個(gè)可見的web應(yīng)用入口

我們先做一個(gè)約定,可以被外部訪問(wèn)到的目錄只有一個(gè),命名為web,放在項(xiàng)目的根目錄下。例如,如果你的web服務(wù)器是Apache,應(yīng)該把DocumentRoot指向web目錄。

因此,將下面的內(nèi)容放在web目錄的index.php文件中:

OurCRM

是的,就是7個(gè)字符的文本文件。畢竟,這就是我們的驗(yàn)收測(cè)試期望的所有內(nèi)容了,正確嗎?

讓我們來(lái)運(yùn)行測(cè)試:

ceptrun

我們得到了如下輸出:

現(xiàn)在,我們需要在項(xiàng)目中使用Yii2了,描述我們功能需求的方法,就是寫一個(gè)完整的端到端測(cè)試。

下一節(jié) 上一節(jié)

本文題目:【翻譯】Yii2第2章用Yii2創(chuàng)建自定義應(yīng)用(第1部分)
鏈接地址:http://muchs.cn/article8/chsiop.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供小程序開發(fā)、用戶體驗(yàn)、外貿(mào)建站、外貿(mào)網(wǎng)站建設(shè)、定制開發(fā)、定制網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化