第十四章 Odoo 12開發之部署和維護生產實例


本文中將學習將 Odoo 服務器作為生產環境的基本准備。安裝和維護服務器是一個復雜的話題,應該由專業人員完成。本文中所學習的不足以保證普通用戶創建應對包含敏感數據和服務的健壯、安全環境。

本文旨在介紹 Odoo 部署的重要配置和最佳實踐,這樣系統管理員可以更好地准備 Odoo 服務器主機。通過本文的學習,我們將能創建一個相對安全的 Odoo 服務器,足夠應對普通的生產環境使用。本文所述並非部署 Odoo 的唯一方法,其它的方法也會同樣適用。

本文主要內容有:

  • 通過源碼安裝 Odoo,主要包含:
    • 安裝依賴
    • 准備一個獨立的系統用戶
    • 通過源碼安裝
    • 設置配置文件
    • 多進程
  • 設置 Odoo 為系統服務,主要包含:
    • 創建 systemd 服務
    • 創建自啟動或 sysvinit 服務
    • 通過命令行查看 Odoo 服務
  • 設置 Nginx 反向代理
  • 配置HTTPS安全服務, 主要包含 :
    • 創建自簽名SSL證書
    • 在 Nginx 上配置 HTTPS訪問
    • 緩存靜態內容
  • 服務器和模塊更新,主要包含:
    • 創建模擬環境
    • 更新 Odoo 源碼

 

開發准備

本章無需使用前面開發的代碼,相關代碼和腳本請見 GitHub 倉庫

通過源碼安裝 Odoo

Odoo 有 Debian 或 Ubuntu的安裝包,使用它可以實現工作服務進程以及在系統啟動時自動開啟服務。安裝過程按步驟即可,在https://nightly.odoo.com/上可以找到相關信息。上面還有CentOS的rpm文件以及 Windows 的.exe 安裝包。

雖然這樣安裝 Odoo 很容易也很方便,大多數人傾向於部署和運行版本控制的源碼來進行集成。這樣能更好地控制部署內容,並且在生產環境中也更易於管理代碼的變更和修復。

安裝依賴

使用Debian發行版時,默認登錄用戶為帶有管理員權限的 root,這時命令行顯示的為#。在Ubuntu系統中,禁用了 root 賬號,在安裝時配置的初始用戶可通過 sudo 來運行 root 權限的命令。首先我們應更新包索引,然后執行升級來確保所有安裝的程序是最新的,命令如下:

下一步,我們將安裝PostgreSQL數據庫,並讓當前用戶成為數據庫超級用戶,命令如下:

我們將通過源碼運行 Odoo,但在那之前,我們需要安裝所需依賴。以下是所需的Debian包:

還應記得安裝打印報表所需的wkhtmltox,命令如下:

注意安裝包時可能報依賴錯誤,像這里最一條命令會強制這些依賴的安裝並正確完成安裝。

現在我們就只缺少 Odoo 所需要的 Python 包了,它們大多數都有Debian或Ubuntu系統包。官方Debian安裝包使用到這些,可在Odoo 源碼debian/control文件中找到這些包名。但是這些 Python 依賴也可以通過PyPI(Python Package Index)直接安裝。所要求的包和通常基於 Python 的項目一樣在 Odoo 的requirements.txt文件中。我們可以使用如下命令安裝這些包:

在Ubuntu 18.04中,最后一條命令可能會打印了紅色的警告,內容是PyYAML 和pySerial的卸載,這在系統中通過包安裝了老版本時會發生。這種警告可以安全的略過。

既然我們有了所有的依賴,安裝了數據庫服務、系統包和 Python 包,我們就可以安裝 Odoo 了。

准備獨立的系統用戶

從安全角度建議使用獨立的用戶運行 Odoo,這一用戶不帶有任何系統的特權。為此我們需要創建系統和數據庫用戶,使用命令如下:

以上odoo 為用戶名,odoo-prod用於運行 Odoo 實例的數據庫名。odoo用戶成為了odoo-prod數據庫的所有者。也就說它對該數據庫有創建和刪除的權限,包括刪除整個數據庫的權限。如果你運行的是多租戶服務器,應為每個租戶創建一個類似 odoo 的指定系統用戶。

小貼士:Odoo的設計即使在系統用戶不是數據庫所有者時也可以正確運行。但這可能會讓設置變復雜,並且固化安全的好習慣是有一個主系統用戶作為數據庫的所有者、為每個實例創建一個指定的不帶有超級用戶權限的系統用戶來運行服務。

注意這些是沒有管理權限的普通用戶,新建系統用戶時會自動創建一個家目錄。比如/home/odoo,用戶可通過~快捷符號來表示自己的家目錄。我們在用戶 Odoo 對應的配置和文件中會使用到它。我們可以使用如下命令來以該用戶打開一個會話:

exit命令終止會話並回到原用戶。

源碼安裝

要不了多久,你的服務就會需要升級、打補丁。這時版本控制倉庫會很有幫助。我們使用 git來從倉庫中獲取代碼,就像我們在安裝開發環境時的操作一樣。下面我將使用 odoo 用戶並將代碼下載家目錄中:

-b 選項確保獲取的是正確的分支,–depth=1選項會忽略修改歷史並僅獲取最新修訂的代碼,這樣下載內容更精簡,速度也更快。

小貼士:git在管理 Odoo 部署版本時是一個非常有價值的工具。注意本系列文章中僅僅涉及到代碼版本管理的冰山一角。想要更加熟悉 git,值得花時間進一步學習,可從http://git-scm.com/doc開始。

到此為止,我們應該已經擁有源碼安裝 Odoo 的所有內容。可通過如下命令以指定用戶會話檢查是否正確啟動並退出:

下面我們將設置一些在系統中使用的系統級別的文件和目錄。

設置配置文件

在啟動 Odoo 服務時添加–save參數會將配置保存到~/.odoorc文件中。我們將以這個文件作為服務配置的初始文件,將其保存到/etc/odoo下,使用命令如下:

這行命令中也會包含服務實例所使用的配置參數。

小貼士:老版本中的.openerp_serverrc配置文件還被支持,找到后會進行使用。如果安裝 Odoo 10或之后版本的服務器上同時還安裝了老版本的 Odoo,可能會引起混淆。這時你會發現–save選項沒有更新.odoorc,而是更新了.openerp_serverrc文件。

下一步我們需要將配置文件放到系統的配置文件目錄/etc 下,命令如下:

以上命令最后一行是可選的,但它提升了系統的安全性。它確保運行 Odoo 進程的用戶可以讀取但無法修改配置文件。這時你將無法修改數據庫主密碼,但在生產服務下這不是什么問題,因為應使用list_db=False服務配置來禁用網頁數據庫管理員。我們還需為 Odoo 服務創建一個存儲日志文件的目錄。這通常放在/var/log目錄下,命令如下:

現在讓我們通過如下命令編輯配置文件並確保已配置了一些重要參數:

以下是大部分重要參數的推薦值:

下面逐一講解:

  • addons_path是一組逗號分隔的用於查找插件模塊的路徑。讀取順序為從左到右,最左邊目錄的優先級最高。
  • admin_passwd是訪問網頁客戶端數據庫管理功能的主密碼。一定要設置復雜的密碼,或者最好是設為 False來關閉這一功能。
  • db_name是在服務啟動時初始化的數據庫實例。
  • dbfilter用於過濾可訪問的數據庫,它是一個 Python 解釋的正則表達式。為使用戶無需彈出窗口選擇數據庫,並使未經身份驗證的 URL 可正常運作,應設置為^dbname$,比如dbfilter=^odoo-prod$。它支持%h和%d占位符,由 HTTP 請求主機名和子域名進行替換。
  • http_port是服務器監聽的端口號,默認使用的是8069
  • list_db = False在 RPC級別和 UI 上屏蔽數據庫列表,並屏蔽數據庫管理界面以及相應的 RPC 功能。
  • logfile是服務日志寫入的位置。對於系統服務,一般位於/var/log文件夾內。如果留空,日志會轉而在標准輸出中打印。
  • proxy_mode在需要反向代理訪問時應設為True,我們需要用到反向代理。
  • without_demo在生產環境中應進行設置,這樣新建的數據庫中不會帶有演示數據。
  • workers的值在大於等於2時啟用多進程,一會兒我們會進一步的討論。

ℹ️Odoo 10中引入http_port參數來替代老版本中使用但現在已淘汰了的xmlrpc_port參數。

從安全角度看,admin_passwd=False和list_db=False選項尤為重要。它們屏蔽掉對數據庫管理功能的網頁端訪問,在生產環境和面向外網的 Odoo 服務中都應進行設置。

以下也是會用到的參數:

  • data_dir是會話數據和附件存儲的路徑,記住將備份放在這里
  • http_interface設置監聽的地址。默認監聽0.0.0.0,但在使用反向代理時應設置為127.0.0.1來僅響應本地請求。Odoo 11中引入它來代替淘汰了的xmlrpc_interface參數。

我們可通過-c或–config選項來檢查運行服務的設置:

通過上述設置運行 Odoo 不會在終端中有任何輸出,因為修改都寫到了配置文件中定義的日志文件中了。要追蹤服務的操作,我們需要在終端中運行如下命令:

Odoo 12開發之部署和維護生產實例

有時可能會需要將日志輸出到標准輸出中,最好的方法是復制一份不帶logfile選項的配置文件。

小貼士:要在同一個終端窗口中運行多個終端會話,可以使用tmux這樣的應用或者GNU Screen。可以使用Byobu,它基於GNU Screen或Tmux提供了好看的用戶界面。

多進程工作進程

生產實例可能會處理大量的工作負載。默認服務運行單進程並只能使用CPU 的一個核心來處理請求,這是因為Python語言的全局解釋器鎖(GIL)。但是可使用多進程模式來處理並發請求,來充分利用多核的優勢。workers=N選項設置使用的工作進程數,作為一個參照,可設置為1+2*P,其中 P為處理器的核數。最佳設置需要根據具體情況進行調優,因為這取決於服務器的負載以及多少其它像PostgreSQL這樣大負載服務在運行。

為負載將workers設置高比低好,最低值應為6,因為這是大多數瀏覽器的並行連接數,最大值通常受服務器的 RAM 所限。普通使用模式的經驗是,Odoo服務應能處理(1+2*P)*6個並發用戶。

還有一些limit-配置參數可用於調優工作進程。在達到這些值時工作進程會被回收,相應的進程會停止並啟動一個新進程。這可以防止服務器內存溢出以及防止某一進程過度使用服務器資源。

官方文檔中對工作進程參數調優也給出了一些很好的建議,欲知詳情,請參照官方文檔Odoo 部署

設置 Odoo 為系統服務

現在我們需要將 Odoo 設為系統服務,並在系統啟動時自動開啟。

在Ubuntu或Debian中,init程序負責服務的啟動。Debian或其分支操作系統曾使用過sysvinit,Ubuntu曾使用過兼容的名為Upstart的啟動程序。但最近都進行了修改,最新的Debian和Ubuntu發行版的init程序都使用了systemd。這表示現在有兩種方式來安裝系統服務,你需要根據操作系統的版本來選擇正確的方法。Ubuntu 16.04或之后的版本中應使用systemd,但是很多雲服務商還在使用更早的版本,所以很有可能你也會使用到這些老版本。要檢查系統中是否使用systemd,可使用如下命令:

這條命令會打印當前使用的 init 程序的文檔,然后就可以查看所使用的啟動服務。

ℹ️Window的子系統(WSL) 中的 Ubuntu環境僅適用於開發,它有可能發生些異常問題,完全不適合用於運行生產環境。在寫本文時,man init顯示啟動服務為systemd,但並不能安裝systemd服務,反而安裝sysvinit服務時是正常的。

補充:如出現-bash: man: command not found,則通過sudo apt install man -y來執行安裝

創建systemd服務

如果你使用的是較近的操作系統,如Debian 8或Ubuntu 16.04,你的啟動服務就應該是systemd。要在系統中添加服務,只需創建一個描述服務的文件。我們創建/lib/systemd/system/odoo.service文件並加入如下內容:

 

小貼士:Odoo源碼中在debian/下包含一個odoo.service文件示例。你可以不用新建方件,直接把拷貝該文件然后進行所需修改。至少需要根據設置來修改ExecStart選項。

下一步我們需要使用如下命令來注冊這個新服務:

使用如下命令啟動該服務:

使用如下命令檢查該服務狀態:

Odoo 12開發之部署和維護生產實例

最后,如需停止服務,請使用如下命令:

 

創建Upstart或sysvinit 服務

如果你使用更老的操作系統,如Debian 7或Ubuntu 15.04,那么很有可能需要使用sysvinit或Upstart啟動服務。就創建系統服務而言,兩者的作用一致。一些虛擬專用服務器(VPS)服務還在使用老的Ubuntu鏡像,所以在碰到這種情況時可以通過以下方式部署Odoo服務。

Odoo源碼中有一個init腳本用於Debian發行包,我們僅需做一些小修改來使用它創建啟動服務:

現在你可能需要查看一下init腳本的內容,主要的參數都在文件上方定義的變量中,如下例所示:

這些變量應該足夠使用了,接下來我們將使用它們的默認值進行設置,但你可以根據自己的需要進行修改。變量USER是運行服務的系統用戶,我們前面已經創建了一個odoo用戶。變量DAEMON是可執行服務的路徑,我們啟動 Odoo 的文件在不同的路徑下,但可創建以下軟鏈接:

變量CONFIG是我們需要使用的配置文件。在前面一節中,我們在默認配置的路徑/etc/odoo/odoo.conf下創建了配置文件。最后變量LOGFILE是存儲日志文件的路徑。配置的路徑/var/log/odoo我們在定義配置文件時進行了創建。

現在我們應該可以像下面這樣來啟動和關閉 Odoo 服務了:

關閉服務方法相似,命令如下:

Ubuntu中可使用 service 命令:

現在我們需要在系統啟動時自動開啟服務,通過如下命令實現:

這時,重啟服務器 Odoo 服務就會正常地自動啟動了。是時候測試下一切是否都如預期一樣了。

使用命令行檢查 Odoo 服務

現在我們可以確定Odoo實例是否運行以及是否能正常對請求進行響應。如果Odoo正常運行,我們應該可以得到響應並且日志文件中不會報錯。在服務器上通過如下命令可檢測 Odoo 是否對HTTP請求進行響應:

此外通過如下命令可查看日志文件的內容:

你還可以使用tail -f 來實時查看日志文件中新增的內容:

 

設置 Nginx 反向代理

雖然 Odoo 自身可以輸出網頁,但強烈建議在其上加一層反向代理。反向代理作為一個中間層來管理客戶端所發送請求以及 Odoo 服務作出響應之間的數據流。使用反向代理有諸多好處。

從安全角度考慮,有以下幾點:

  • 處理並加固HTTPS協議來對數據流加密
  • 隱藏內部網絡特征
  • 作為應用防火牆,限制所接受處理的 URL

然后從性能角度考慮,反向代理可提供如下顯著的改進:

  • 緩存靜態內容,因而降低 Odoo 服務器的負載
  • 壓縮內容來加快加載時間
  • 作為負載均衡器,在多台服務間分配負載

Apache是在考慮反向代理時的一個常用選擇,Nginx 是近期在技術圈被熱議的對其的替代。此處我們使用Nginx作為反向代理,並展示如何使用它來實現上述討論的安全和性能方面的功能。

首先,我們應當安裝Nginx,我們需要它監聽默認的HTTP端口,所以需要確保沒有被其它服務所占用。執行如下命令應該會報錯:

如果沒有收到錯誤,應當禁用相應服務來讓Nginx使用該端口。例如,關閉已有的Apache服務,使用sudo service apache2 stop。更好的選擇是從服務器上刪除該服務或重新配置讓其監聽其它端口,這樣Nginx就可以正常使用HTTP和HTTPS端口(80 and 443) 了。

一旦完成上述操作,就可以安裝Nginx了:

要確定Nginx是否正確運行,通過瀏覽器訪問或在服務上執行curl http://localhost應該可以得到一個Welcome to nginx頁面。

Odoo 12開發之部署和維護生產實例

Nginx配置文件和Apache的方式基本相同,存儲在/etc/nginx/available-sites/中,並可通過在/etc/nginx/enabled-sites/中添加軟鏈接來激活。注意應同時關閉Nginx安裝時默認帶有的配置:

使用nano或vi等編輯器來編輯 Nginx配置文件:

一個基本的針對Odoo服務的Nginx配置文件如下例所示:

補充:添加域名請在server 配置區內添加對 server_name 的配置

首先為Odoo服務添加了upstream配置,監聽了默認端口8069和8072。8069用於網頁客戶端和RPC請求,8072用於多進程時 Odoo 實時消息所需的長輪詢(long polling)請求。

Nginx應在默認HTTP端口80上接收訪問流量,然后重定向到upstream odoo服務中。這在server配置區中進行了定義。/longpolling 地址的訪問流量會傳遞到upstream odoochat,剩余的流量則傳遞到upstream odoo。這里我們還添加了一些請求頭的信息,這樣 Odoo 后台服務就會知道這些是經過代理的流量。

出於安全考慮,應確保proxy_mode參數設為True。這是因為在Nginx作為代理時,所有的請求都會認為是來自本地而不是遠程 IP 地址。在代理中設置X-ForwardedFor頭以及啟動–proxy-mode可解決這一問題。但是,如果不在代理級別強制header就啟用–proxy-mode 會讓其他人可以偽裝遠程地址。

在配置文件的最后,可以看到兩條gzip相關的命令,它們用於對一些文件進行壓縮,提升性能。可通過如下命令測試配置是否正確:

如果出現錯誤,請檢查配置文件中輸入是否正確。常見的問題是默認的HTTP被其它服務所占用,如Apache或默認的Nginx網站,所以在重啟Nginx服務前先通過本文中的命令確保並沒有這種問題。在完成處理后,可使用如下命令重新加載新的配置:

如果操作系統使用的是systemd,上述命令正確的版本應該是:

通過如下命令可確認 Nginx 是否將訪問流量重定向到了后台Odoo服務中:

Odoo 12開發之部署和維護生產實例

配置HTTPS安全服務

網站數據不應在因特網中以普通文件進行傳輸,在將Odoo網頁服務暴露在網絡中時,我們應使用HTTPS協議來對數據進行加密。有時可使用自簽署證書。但注意自簽署證書可能會帶來安全風險,比如中間人攻擊(Man-in-the-Middle Attack),因此有些瀏覽器會不接受該證書。

更健壯的解決方案是使用認證的證書機構所簽署的證書,在運行商業或電商網站時這就尤為重要了。

小貼士:Let’s Encrypt服務提供免費的證書。Odoo 有現存插件模塊處理對Odoo服務SSL證書的自動請求,但在寫本文時,還未移植到Odoo 12中,可訪問 GitHub 進一步了解。

創建自簽署 SSL 證書

下一步,我們應安裝證書來啟用SSL。創建一個自簽署證書,可使用如下命令:

上述命令創建一個/etc/ssl/nginx目錄以及不帶密碼的自簽署SSL證書。在運行openssl命令時,會要求用戶輸入其它信息,然后會生成一個證書和密鑰文件。最后,將這些文件的所有權賦予用於運行網頁服務的www-data用戶。

在 Nginx上配置HTTPS訪問

既然我們已經有了SSL證書,就可以配置 Nginx 來使用它了。要強制使用HTTPS,需要將所有的 HTTP 訪問重定向到HTTPS。將前面的server區中替換為如下內容:

現在,如果重新加載Nginx配置並在瀏覽器中訪問服務的話,將會看到http://地址被轉換成了https:// 地址。但該地址不會返回任何內容,我們需要正確地配置HTTPS服務,可通過添加如下服務器配置來實現:

以上配置代碼會監聽HTTPS端口並使用/etc/ssl/nginx/ 證書文件來對數據進行加密。這與我們在設置 Nginx 反向代理中看到的server 配置區相似。如果重新加載配置,我們的 Odoo 服務將通過HTTPS進行運作,如以下命令所示:

最后部分的輸入可用於確認Odoo客戶端正通過HTTPS進行訪問。

小貼士:在更早的Odoo鏡像中,PosBox僅在HTTP模式下生效,這就需要在 Nginx 中添加對/pos/ 鏈接的例外處理。Odoo 10及之后的鏡像中包含了自簽署證書來讓PosBOx和IoT Box可通過HTTPS進行通訊,這一修改在 GitHub 中引入。

Odoo 12開發之部署和維護生產實例

緩存靜態內容

我們可以配置 Nginx 來緩存服務端靜態文件,這樣再次請求時就可以訪問Nginx 中的緩存,而無需將請求傳遞到upstream odoo服務中。啟用靜態內容緩存可帶來更快的響應時間並減少 Odoo 服務的工作負載。要啟用這一設置,在location /longpolling區之前加入如下代碼:

通過這一些命令,靜態數據就可以緩存60分鍾了。在這個期間的其它請求Nginx 會直接使用緩存進行響應。

服務和模塊更新

一旦 Odoo 服務運行了一段時間,就會需要對其進行升級。這包括兩個步驟:獲取服務或模塊的新版本、執行安裝。

創建分階環境

如果你按照通過源碼安裝 Odoo一節正確地進行了安裝,應該就可以在暫存區倉庫中獲取並測試新版本源碼。強烈建議創建一個生產環境數據庫的拷貝,並使用它進行升級測試。如果odoo-prod是我們的生產環境數據庫,可通過如下命令創建一個拷貝odoo-stage:

在使用以上數據庫拷貝之前,應進行清理,比如停止計划動作、關閉 email 服務(包含發送和接收消息)。根據你的設置來執行這些指定步驟,但通常可使用自動化腳本來執行。記住psql可用於在命令行直接執行SQL命令,如psql -d odoo-stage -c “<SQL命令>”。

 小貼士:可通過createdb命令來更快地創建拷貝:createdb –owner=odoo –template=odoo-prod odoo-stage。但需要說明的是要運行該命令,不能有任何對odoo-prod數據庫的連接,因此需要停止Odoo生產環境的服務。

更新 Odoo 源碼

我們使用git pull 命令來從GitHub倉庫獲取最新的Odoo源碼。在那之前,我們可以使用git tag命令來為當前使用的提交創建一個標簽,這樣可以可容易的對更新進行撤銷,命令如下:

要讓代碼修改生效,我們需要重啟Odoo服務。而要使用數據文件的修改生效,需要對模塊進行升級。通常對Odoo穩定版本的修改都是代碼的修復,因此無需冒險執行模塊升級。如果需要對模塊升級,可使用-u <module>附加參數,或者是-u base,它將升級所有模塊。

現在可以啟動Odoo的分階服務了,它將使用在分階數據庫上使用升級代碼:

Odoo 分階服務通過在8080端口上進行配置。可通過瀏覽器訪問http://xxx:8080來檢查升級代碼是否正確運作。如果出現了錯誤,可通過如下命令來返回上一個版本:

如果一切運行都如預期,則可安全地執行生產環境服務的升級,通常是通過重啟來實現。如果想要執行實際的模塊升級,建議的方法是停止服務、運行升級、再重啟服務,命令如下:

記住對在用Git 版本進行記錄,可通過 git checkout回到修改前,這讓我們可以在需要的時候進行回滾。強烈推薦在執行數據庫升級前保存備份。在完成之后,可使用 Git 拉取新的版本到生產倉庫並完成升級:

無需頻繁進行升級,但也不建議等上一年再進行升級。每幾個月進行一次升級。還要記得重啟服務來啟用代碼升級,但對模塊升級則並非如此。但如果需要進行指定的漏洞修復,可以更早的進行升級。還應關注公開渠道對 Odoo 安全漏洞的披露,發 GitHub 上 Odoo 的Issues,具體可查看Security標簽,或者是官方的郵件列表,可通過https://www.odoo.com/groups進行訂閱。

作為一項服務,企業版用戶會更早地收到郵件通知來警報這一類問題。

總結

在本文中,我們學習了在Debian系生產服務器中設置和運行 Odoo 所需的其它步驟。我們一起了解了配置文件中最重要的設置項,並學習了如何擅用多進程模式。為提升安全性和擴展性,我們還學習了如何使用 Nginx 來作為 Odoo 服務處理之上的反向代理。

本文涵蓋了運行 Odoo 服務並向用戶提供穩定、安全服務的基礎知識。要更多地了解 Odoo,可參考官方文檔。其中更深入的講解了一些課題,並包含了一些本系列文章未涉及的課題。

還有一些有關 Odoo 的出版圖書還助於你的學習。Packt Publishing中有一些相關書籍,具體來說Odoo Development Cookbook包含了本系列文章未討論到的高級課題。

最后,Odoo是一個擁有活躍社區的開源產品。參與、提問並回饋社區不僅有助於學習,還有助於建立人脈。說到這,就不能不提 Odoo 社區聯盟(OCA),它倡導協作並提供高質量的開源代碼,可訪問https://odoo-community.org/做更進一步了解。

擴展閱讀

以下Odoo官方文檔的內容可作為本文討論課程的補充材料,來幫助獲取額外的參考:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM