工作中的記錄(持續更新,從入行到退休)

2019年

11月

11.4
組裝電腦、配置各種環境、一天就結束了

11.5
學習行雲的SQL和pl/sql,這些沒啥難度,看看就OK

11.7
查看一個開源ast框架的源碼,編譯原理的東西忘光了,不過還好,影響不是很大。

字符流 - 詞法分析(將每個char轉換成token)- 語法分析(也就是分析每個token)- 語義分析(assign、compound、控制循環語句)- 中間代碼生成(SymTab符號表就這一層,這裏會生成一個ast)- jvm再去遍歷執行ast

11.11
今天是雙十一啊,昨天買東西,買的有點晚,今天早上又擠地鐵,嗯嗯微笑臉,北京的早高峯說實話還是讓人有點不敢恭維,等畢業後趕快找個離公司近的房子,不過在地鐵上我感覺是我一天心裏最愜意的時光,聽蔣勳老師解說紅樓夢,真的是太喜歡他了。還有最近這些天下班回去總是看比賽,感覺這麼下去不行啊,得趕快調整一下。

不明白Pascal中的public static void main(String args[])方法實例化new Pascal(operation, path, flags)的時候要用args[]參數,還有設置變量i的作用。

還有各種語法樹也不明白,難受啊!

現在明白了,越往後看,對前面的整個架構的設計理解越清除。

11.12
不明白下面這段代碼:

	Object body[] = (Object[]) message.getBody();
				int line = (Integer) body[0];
				int position = (Integer) body[1];
				TokenType tokenType = (TokenType) body[2];
				String tokenText = (String) body[3];
				Object tokenValue = body[4];

但是:

	public Object getBody() {
					return body;
				}

Object變成Object[]了,什麼鬼?

這個問題已經解決,代碼中給 body 傳參的時候,傳的是如下這麼一個實參:
new Object[] { token.getLineNumber(),token.getPosition(), token.getType(), token.getText(), token.getValue() }
body被定義爲object類型,傳的參數是一個數組,在Java中,數組本身就是一個對象,所以這裏的傳值方式是絕對OK的!
比如下面代碼不會報錯:Object ob = new String[] { “1”, “2” };
至於這一步:Object body[] = (Object[]) message.getBody();先把它按照多態的方式理解吧,暫且這麼理解,不知對錯,後面再詳細探究!

11.13
不明白下面這種繼承與重寫的關係:

一個父類,有個無參構造方法和一個實例方法;一個子類,有無參構造方法(方法中調用super())和一個重寫父類的實例方法。
當實例化子類時:程序的執行順序是:父類構造方法 -> 子類實例方法 -> 子類構造方法,不理解爲什麼子類實例方法可以在構造方法之前被調用,已整理博客,記得向大佬請教!比如說:Token類的構造方法中有extract();這個方法。

上面理解了,主要還是類加載問題。這種調用方式看似可行,其實沒有啥實際意義(個人理解),子類未實例化之前其父類構造方法中調用該子類的實例方法,實例方法中的成員變量都是未初始化的值,所以沒意義,博客裏面有具體例子https://blog.csdn.net/qq_42570601/article/details/103044178,可能只是表述了現象,未說明原理,等後面變強了在把這個點補補。

對PascalParserTD中的parse()方法,對正確token和錯誤token的處理方法的整體構思理解的模模糊糊,後面反過來看吧!

11.15
這個週末把Java的enum以及相應的集合框架複習複習,徹底搞明白!
發現有人總結的相當奈斯,直接轉過來了:https://blog.csdn.net/qq_42570601/article/details/103620358

11.18
目前從這裏面學到的設計模式有:代理模式、工廠模式、策略模式、觀察者模式、符號表好像用的是一個適配器模式
SymTabImpl這個符號棧表的具體實現方式,看完賦值語句解析,把這個在仔細看看

11.19

一個簡單表達式由一個或多個被加法運算符(additive
operator,加和減都是加法運算符)隔開的term組成。第一個term前面可能有一個加或減號(表示正負)。一個term由一個或多個被操作符隔開的factor組成。factor可以是變量,數字,字符串

11.21
對java的引用傳遞和值傳遞再做一個詳細的探究,public ICodeNode parse(Token token) throws Exception {}這裏如果token被賦值,token實參是不變得但是statementParser.parseList(token, compoundNode, END, MISSING_END)中參數compoundNode是變化的。
OK,理解了,這其實只要看他每次是對堆操作,還是說是隻是改變棧中原來指向堆中的引用值的指向,已整理博客,原來總結過,但是不徹底,這次做補充:https://blog.csdn.net/qq_42570601/article/details/97272225

不太明白序列號到底是幹啥的。

現在知道了他是幹啥的,但不知道是怎麼幹的。

現在都明白了。
已整理博客:https://blog.csdn.net/qq_42570601/article/details/103396656

11.22
對符號表不太理解。

現在wo理解了,嘿嘿嘿!你追我,如果追到我,我就讓你嘿嘿嘿!嘿嘿嘿!

11.26
一直不明白這個同步集合到底是幹啥的synchronize(ConstantDefinitionsParser.CONSTANT_START_SET);他的實現在PascalParserTD中。
好像有點明白了,如果兩個token之間,存在一個或多個非預期的token,這時候可以使用synchronize跳過這些token,並報出錯誤信息,而不影響後面的語句的解析

CONST 的解析
PascalParserTD —— ProgramParser —— DeclaredRoutineParser ——BlockParser —— DeclarationsParser(會根據type分配給具體的類,策略模式)—— ConstantDefinitionsParser

11.27

TYPE 的解析,以subrange(子界)的解析爲例
PascalParserTD —— ProgramParser —— DeclaredRoutineParser —— BlockParser —— DeclarationsParser(這裏會往後面分配,找到等號後面token) —— TypeSpecificationParser(這裏開始對等號後面的type解析,包含簡單類型,數組類型和記錄類型) ——SimpleTypeParser(簡單類型, 包含枚舉和子界)—— SubrangeTypeParser(分析上下界的是否匹配等)——ConstantDefinitionsParser(分析上界或下界的value和type)

11.28
不明白這一步

// 判斷程式是否前向來決定是否創建符號表
		if (routineId.getAttribute(ROUTINE_CODE) == FORWARD) {
			SymTab symTab = (SymTab) routineId.getAttribute(ROUTINE_SYMTAB);
			symTabStack.push(symTab);
		} else {
			routineId.setAttribute(ROUTINE_SYMTAB, symTabStack.push());
		}

已解決,這個就是看一下routineId中是否已經出現過ROUTINE_CODE(相當於一個樹節點),true取出符號表推送進棧,false創建新的符號表推送進棧

Definition 定義類型,比如常量的定義類型是constant,變量的定義類型是var等,或者說是一個程序program。
TypeSpec 類型說明,比如integerType,

明天週五,要去參加一個pg的開源社區會,太興奮了,感謝遠哥給了這次機會。

12月

12.3
寫了個鬥地主發牌功能(可持續、常規、特殊、關照),網絡上面,只要是涉及到機率的東西,幾乎沒有一個是公平的,哪怕是鬥地主發個牌充錢的和沒充錢的就是不一樣,哈哈哈,他在這裏,其實很簡單很簡單:https://blog.csdn.net/qq_42570601/article/details/103370110

12.4
instanceof 父類引用,子類實例,他會對照哪個?

爲什麼持久化的類都要implements Serializable這個接口(實現序列化)?持久化和這個interface到底是什麼關係?
已解決,並整理博客:https://blog.csdn.net/qq_42570601/article/details/103396656

語法樹結構:
SyntaxTree(繼承了hashmap) Statement(他的子類是各種單條語句)
Expression(他的子類是各種表達式)

解析時各類的結構調用:
Task
XcloudParse
ProcedureDeclareStatementParser FunctionDeclareStatementParser PackageDeclareStatementParser ExecutableBlockStatementParser(DECLARE and BEGIN is used)

12.5
不明白下面的參數設置是幹啥的

//參數設置
		List<DispatchParameter> params = new ArrayList<DispatchParameter>();
		DispatchParameter p1 = new DispatchParameter("", "", java.sql.Types.VARCHAR+"",true,false, "p1");
		params.add(p1);
		task.setParameters(params);

12.#
請了一個星期的假,回去考試,難受,哼,誰都別想阻止我擼代碼!

12.#
從學校回來,這段時間在划水,每天做做畢設,學學基礎,寫寫博客,這麼下去可不行啊,會自閉的!

12.23
他來了,他來了,我的需求他來了。
在這裏插入圖片描述
12.24
現階段所有Parser只需要語法分析,而不再做語義檢測(類型分析),至於類型會交付給後面的am去完成。具體怎麼說呢,比如說,有兩個變量a、b:

	a integer;
	b date;

如果有這種操作:a := b; 原來在編譯階段,是不允許有這種操作存在的,而現階段就可以,是因爲所有對類型的操作等解析完成後由am再去處理。
再詳細說:如果我們聲明一個變量:c integer;現編譯階段,只需要c放進符號表棧就OK,不管他是integer還是number,解析到下文使用它,也只需判斷他有沒有在符號表棧中出現過,如果沒有,就可能是數據庫裏面的東西,或者錯誤,具體由am實現。

12.25
喫完飯看一下OrExpressionParser這玩意的內部實現,感覺他能解析好多表達式、參數、變量啥的

12.27
幾個類的編譯優化,從早上搞到下午三點,然後,然後那幾個類不用了,微笑微笑微笑

回學校考試去嘍!嘿嘿嘿。。。

2020年

1月

1.6
提醒亮哥檢查我代碼的時候,注意一下ArrayEqualNullExpression這種類型的類

總結一下下面兩種方式的區別:leftExpression和rightExpression是父類中的protected屬性,最好整理成博客,還有五六篇博客欠着,難受啊!今晚回去勢必要擼一篇,不然就法喝一瓶可樂,哈哈哈哈哈。

	public BooleanLessEqualBooleanExpression(Expression leftExpression,
			Expression rightExpression) {
		super(leftExpression, rightExpression);
		this.type = Predefined.booleanType;
	}
	public BooleanLessEqualBooleanExpression(Expression leftExpression,
			Expression rightExpression) {
		this.leftExpression = leftExpression;
		this.rightExpression = rightExpression;
		this.type = Predefined.booleanType;
	}

總結如下:

  • 1.子類繼承父類的屬性和方法,並重寫父類的方法,子類修飾符不能比父類方法的修飾符的範圍狹窄。

  • 2.子類繼承父類,子類必須在構造函數中的第一行使用super()來調用父類的構造函數,雖然你有時候沒有寫也能編譯通過,那是系統默認調用了super。

    關於super的調用,有以下說明:

    • 1.父類沒有寫構造函數(系統默認有一個無參構造函數),或者父類只有一個無參構造函數,則:子類可以不寫構造函數(可以理解爲:子類的系統默認構造函數,默認調用了super();),
      也可以寫有無參或者有參構造函數,而且不用調用super,系統會默認調用。

    • 2.如果父類有有參構造函數,沒有無參構造函數,則:子類不能有無參構造函數,可以有有參構造函數且必須在有參構造函數中顯示的調用父類的有參構造函數,即super(參數名)。

    • 3.如果父類既有有參構造函數,又有無參構造函數,則:子類可以有有參也可以有無參,且可以使用super調用父類的有參無參構函數,也可以不調用super,使用this.屬性 = 形參,的方式去實現有參構造函數。

    • 4.如果父類的構造函數只有一個,且修飾符是private,則:不可以被繼承。

從上面的總結可以看出,這兩種方式本質上是沒有區別的,就是如果父類中只有有參構造沒有無參構造,第一種方式會報錯。

1.7
《東京物語》這週末看一下這個電影,聽蔣勳老師提到的,男神說的東西,從沒讓我失望過。

ExponentExpression這個類的語義檢測不會寫。OK了
EqualExpression中原來的語義檢測感覺邏輯有點問題。歐克了
IsNullExpression 和 IsNotNullExpression 感覺自己寫的有問題,又好像沒問題

1.8

ExecuteImmediateBulkStatementExecuteImmediateStatement的子類,兩者語義檢查的不同地方在於executeStatement.setSize(1);這個屬性是幹啥的呢?在statement類裏面。

知道了,相當於一個標誌符,在執行階段 起作用,標誌一個expression或者statement是否執行過。

1.9
Parser時調用idParseHelper去Parser,返回的結果要在語義檢查階段要做具體的instanceof,不太明白爲什麼這麼做,只知道這樣Parser是不能確定類型的,源碼太多了,不想去看了,。

明天來了把ExceptionRaiseStatementParser的新Parser寫一下,ExecuteStatementParser的新Parser也有問題,ExecuteImmediateStatementsemanticCheck要再加一下Parser中的東西。

晚安!好夢,等等,別好夢,不想做夢,夢裏全是些亂七八糟讓人頭禿的東西。還有幾分鐘下班,聊兩句,最近一直看弗洛伊德心理學,弗洛伊德把人的精神世界分爲意識、下意識、潛意識這三層境界。他說夢是人與潛意識之間溝通的一道橋樑,潛意識裏存在的東西,在你的意識境界對其是不具有主動性的,但是又不會脫離意識存在。也就是說,你在平時生活中是無法控制潛意識也無法感受到他的存在的,比如當你聽到家人朋友出現什麼意外時,你會有害怕、緊張、不安的表現,而這種表現,則源於潛意識。潛意識是一種很奇妙的存在,有時候,有時候就下班時間到了,溜了溜了,我最怕遇到,那個潛意識世界的你。

1.10
遠哥說明天要onebyone的來個facetoface的交流,我現在雙休,明天不在公司,下週一希望他給我補上,哈哈哈!提前列個表,畢竟這種機會不多:

  • 1.現在所從事的方向未來的發展路線和就業領域。
  • 2.相比於其他方向,如web,我們有哪些優劣勢。
  • 3.我應該有個什麼樣的職業規劃,在若干年後自己的競爭力不減而增。
  • 4.維持工作和生活之間平衡的方法,尤其是以後成家之後。

編程思想第65頁,關於equals方法,這個東西我原來總結過,但是我好想還沒有看過Object源碼是怎麼實現這個方法的,今天不看源碼了,一個都不看,所以先記這裏吧!

編程思想看到第72頁,3.1.11 。

1.13
今天早上來沒啥需求,就一直看編程思想:)
假若對主數據類型執行任何算術或按位運算,只要它們“比int 小”(即 char,byte 或者short),那麼在正式執行運算之前,那些值會自動轉換成int。
若想在一次布爾測試中使用一個非布爾值——比如在 if(a)裏,那麼首先必須用一個條件表達式將其轉換成一個布爾值,例如 if(a!=0)。
主(數據)類型能從一個“較小”的類型自動轉變成一個“較大”的類型。涉及過載問題時,這會稍微造成一些混亂。
不能根據返回值類型來區分過載(重載)的方法。

arrayExpression包下沒有寫語義檢測(因爲沒有新Parser)的類有:
ArrayConstructorFunctionExpression
VarrayConstructorFunctionExpression

今天遺留問題:

  • ArraySetExpression的sm已經寫完,後面還有三個沒寫-FactorExpressionParser中的Parser有問題,問題出在寫這個Parser的
  • 沒有重寫Parser中調用的副Parser
  • 感覺今天寫的sm返回的節點應該再加一個類型屬性

晚安

1.14
FactorExpressionParser這個類中的parseSetArray方法有問題,我根據這個Parser寫了ArraySetExpression,不知道有沒有問題

完成任務1:arrayExpression包下十多個類新架構的語義檢測

先在ArrayTypeDeclareParser裏面把新的Parser寫好,再從TypeDefinitionParser裏面去寫ArrayTypeDeclareParser的調用
解析的時候這條語法是可以的,但是行雲的文檔裏面沒有這種語法,不知道對錯!TYPE type_name IS ARRAY(limit) OF pType [NOT NULL];
這條語法是OK的,行雲文檔少寫了個括號。

完成任務2:新架構下數組聲明的解析與語義檢測

TypeDefinitionParser類中數組的Parser部分感覺我寫的很簡單,和上面遊標和記錄相比;

1.15
只要沒有任務,就趕快學習:)
假定我們在一個方法的內部,並希望獲得當前對象的句柄。由於那個句柄是由編譯器“祕密”傳遞的,所以沒有標識符可用。這個時候就可以用this關鍵字,this 關鍵字(注意只能在方法內部使用)
可爲已調用了其方法的那個對象生成相應的句柄。可象對待其他任何對象句柄一樣對待這個句柄。很多時候,你不用this編譯器也能明白,但也有特殊情況,比如需要返回當前對象的時候。

昨天寫的代碼出現了三個問題:

  • 1.當前Parser調用下一層Parser時,是不喫掉下一層Parser要處理的token的,TypeDefinitionParser中解析變長數組時我這麼做了。
  • 2.如果在變長數組的not null 後面跟一個INDEX BY indexType;我的解析是不會報錯的,應該報錯。
  • 3.聲明生成的樹沒有辦法取到,要在符號表項裏面加一個類型名。

編程思想看到105頁,困得不行了,看不動了!

1.16
Object中的finalize()到底是怎麼實現的呢?看了半天也沒看懂,源碼是這樣的protected void finalize() throws Throwable { },應該是由子類去實現

ForCursorStatementParser第84行symTabStack.push();

SyntaxTree中的semanticCheck方法是不是應該return this;先別寫成return this,前期測試的時候可以暴露那個語法樹沒實現,後期測穩定了,可以寫

編程思想107頁!
設計模式17頁!

1.17
以下類沒有做語義檢測:
AssignmentStatement,賦值語句,例如a:=4

不太理解下面類幾個類的語義檢測:
DeclareVariableStatement,明白了啦

1.19
CaseExpression這個類STG我是直接按照別人寫的SC寫的,後面反過來檢查一下

在SC過程中,調用FDS計算(支持與不支持兩種情況),而在STG過程中,只new了一種情況的類有:

ConcatExpression
DivExpression
ExponentExpression
ModExpression
SubExpression
EqualExpression
GreaterExpression
GreaterEqualExpression
LessExpression
LessEqualExpression
NotEqualExpression

2月

2.4

URLClassLoader
ForwardingJavaFileManager
SimpleJavaFileObject

這幾個類下來仔細看看

2.5
任務:
sysfunction包下的系統函數語法樹部分沒有實現語義檢查。
打算張河和黃奇齊寫完,跑一下內測,完了下週集中改一下。

2.6

SystemFunctionExpression
Sys_ts_SystimestampExpression
Sys_ts_LocaltimestampExpression
Sys_ts_CurrenttimestampExpression
Sys_RegexpLikeExpression 沒有行列號在old-parser階段
Sys_NvlExpression
Sys_LeastExpression
Sys_GreatestExpression
Sys_ExtractExpression 其中有個變量 TypeSpec input = null;沒有用到
Sys_Date_SystemDateExpression
Sys_Date_CurrentDateExpression Sys_CoalesceExpression

2.9
javaCompiler簡單來說就是一個用來調用java語言編譯器的接口,我們使用它可以實現對其他路徑下或者遠程代碼的編譯。

顯然我們可以實現這樣一種操作,將一串符合java語法的字符串寫入一個java文件中。然後利用javaCompiler編譯此文件。最後通過

反射的方法實現對此文件的運行(online judge)。

2.10

create or replace procedure proc_example3(res out varchar)
is
	 appraisal VARCHAR2(20);
BEGIN
	appraisal :=‘success’;
res := appraisal;
END;

ProcedureDeclareStatement 過程聲明表達式:
有過程名、參數列表、可執塊,可以根據過程名創建一個static方法,參數列表作爲方法的參數,可執行塊作爲方法的方法體;
參數列表有IN、OUT、INOUT三種參數類型,in類型直接作爲參數即可,

ParameterDeclaration 參數聲明表達式

2.13
xcloud控制整個流程
parser:主要是解析,符合語法就OK
am:蒐集源數據對象,主要是數據庫對象,表什麼的。
sc:語義檢查
stg:語法樹下推
IdParseHelper:比較重要的一個解析,下來仔細看看
IDExpression:比較重要的一個sc階段,下來好好看看

編譯優化內測,有兩個問題沒能解決:一個是IDExpression中可能類型定製的問題,另一個bug稍多些,解決了一部分,還有一部分尚未定位。

自己能夠獨自解決一些比較局部,屬性較少的語法樹相關問題,如果涉及到那些控制範圍比較大,parser或者sc很多的語法樹,就會定位不到問題或者定位到了解決不了,需要詢問亮哥才能解決。還有自己有兩個點做的不好,一個是整體架構的細節瞭解或者掌握的太少,另一個是在UI上面做的plsql語法練習太少,內測時感受會很明顯,以後會補強這方面。

2.10
將下面這段過程轉成JavaSource:
create or replace procedure proc_example3(var in int,res out varchar)
is
num int;
appraisal VARCHAR2(20);
BEGIN
num := 10 + var;
appraisal := ‘success’;
res := appraisal;
END;

ProcedureDeclareStatement 過程聲明表達式:
有過程名、參數列表、可執塊,可以根據過程名創建一個static方法,參數列表作爲方法的參數,可執行塊作爲方法的方法體;
參數列表有IN、OUT、INOUT三種參數類型,in類型直接作爲參數即可,

ParameterDeclaration 參數聲明表達式

2.13
xcloud控制整個流程
parser:主要是解析,符合語法就OK
am:蒐集源數據對象,主要是數據庫對象,表什麼的。
sc:語義檢查
stg:語法樹下推
IdParseHelper:比較重要的一個解析,下來仔細看看
IDExpression:比較重要的一個sc階段,下來好好看看

調試經驗總結:
首先debug具體哪裏報錯,確定那是一個什麼問題,然後分析出現這個非預期的結果可能在哪個環節出錯,最後在具體的環節去針對解決。

2.14
UDFArrayTest UDFTest21() 還有問題,要跟着舊parser把新的parser和sc再過一遍

跟package有關的暫時都不用管
SQL報錯都不用管,行雲目前不支持

系統函數測試記錄:
Sys_Stddev_Samp_Test:只報SQL錯誤,其他ok
First_ValueTest baseTest1():解析執行沒錯誤,但是返回的數據與預期不符,expected:<10> but was:<0>,上個版本是ok的。
SysFunctionTest BaseTest14();expected:<[NUMBER]> but was:<[LONG]>
BaseTest17();expected:<300> but was:<0>
BaseTest18();expected:<[NUMBER]> but was:<[DOUBLE]>
BaseTest19();expected:<[NUMBER]> but was:<[LONG]>
BaseTest21();expected:<1> but was:<0>
BaseTest25();expected:<1> but was:<0>
BaseTest26();expected:<1> but was:<0>
Sys_Stddev_pop_Test:只報SQL錯誤,其他ok
Sys_CeilExpressionTest2 test_1():這個運行結果和上個版本一樣,解析和執行都不報錯,但是條條是紅色的,那個報錯日誌上報的是類型不匹配
java.lang.Long cannot be cast to java.lang.Double

syntaximpl測試記錄:

2.17
在RecordAndFieldSCUtil的recordAndFieldSC方法中
baseTest01

在FDSManager類TypeSpecToString方法的type參數爲null:有可能是ConstantExpression的parser沒有settype
baseTest54

在procedure中調用PACKAGE,行雲現階段不支持PACKAGE,暫不處理:
baseTest103
baseTest104
baseTest118

2.21
這兩個是記錄子域那塊有問題,沒做好,下來一定要把這個改好:
[ERROR] Fun_IntervalTest.Test1:77 ERROR-1245214:Parse_error com.bonc.xcloud.procedure.intermediate.syntax.syntaximpl.xexpression.SqlIDExpression cannot be cast to com.bonc.xcloud.procedure.intermediate.syntax.sql.SqlVariableExpression at Name:PRO_PUT_LINE_LGP_106 Line:28 Column:5
[ERROR] Fun_IntervalTest.tset3_3:238 ERROR-1245199:Access_INTO_null java.lang.NullPointerException

2.24
1.腳本寫2個以上的不看
2.有package的不看
3.調用數據庫的過程或函數,裏面的參數是複合類型比如記錄、數據啥的,這種也不看

3月

3.4
1.PL/Cache存儲過程元數據緩存
2.帶有複合類型參數的過程、函數或者包,保存時以JSON格式描述複合類型或者包頭信息,並將其保存到元數據中。

3.10
idparsehelper中關於procedure的parse存在問題

3.12
存儲過程編譯調用過程、函數或者包,不再需要獲取源碼重新解析,獲取到的元數據信息中已有對應描述,
既可作語義檢查,提高編譯速度;實現上述功能的同時,還要保證編譯優化版本預存的json和語義檢查要
兼容舊版本的sql developer和存儲過程。目前因爲歷史遺留問題,預存功能中產生了很多中間結構去做語法
樹到json的轉換,當前版本按照概要設計的思想進行,下版本任務模塊預存功能的轉json接口將轉移到存儲過程計算引擎中實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章