Liferay中portal-model-hints.xml文件的作用
MSN羣中Jacky Miao問到這個問題。自己也不瞭解,於是乘此機會讀了一下源代碼。
本文是從Word中拷貝的,因此沒有修改標題編號。
1.1 基本情況
經過檢查,在liferay項目中,共有兩個類似文件:portal-ejb.jar中的portal-model-hints.xml和ext-ejb.jar中的ext-model-hints.xml。
文件的內容,是所有 model 對象的XML格式表述。如,ext項目中的相應內容:
<?xml version="1.0"?>
<model-hints>
<model name="com.ext.portlet.reports.model.ReportsEntry">
<field name="entryId" type="String" />
<field name="companyId" type="String" />
<field name="userId" type="String" />
<field name="userName" type="String" />
<field name="createDate" type="Date" />
<field name="modifiedDate" type="Date" />
<field name="name" type="String" />
</model>
</model-hints>
Portal自帶的portlet留言板中的一個model的定義爲
<model name="com.liferay.portlet.messageboards.model.MBCategory">
<field name="categoryId" type="String" />
<field name="groupId" type="String" />
<field name="companyId" type="String" />
<field name="userId" type="String" />
<field name="userName" type="String" />
<field name="createDate" type="Date" />
<field name="modifiedDate" type="Date" />
<field name="parentCategoryId" type="String" />
<field name="name" type="String" />
<field name="description" type="String">
<hint-collection name="TEXTAREA" />
</field>
<field name="lastPostDate" type="Date" />
</model>
該文件跟ext-hbm.xml是類似但又各不相同的兩個文件。Hbm文件是hibernate的描述文件,跟數據庫是對應的。Model-hints主要是反映model的結構,不一定是數據庫中的。
檢查這個文件的內容,除了model的定義及其字段的定義之外,在一些字段上,會有一些hint信息,主要分爲三類:
l 在文件最開始的hint-collection定義
<hint-collection name="BLOB">
<hint name="max-length">2000000</hint>
</hint-collection>
<hint-collection name="TEXTAREA">
<hint name="display-height">105</hint>
<hint name="display-width">500</hint>
<hint name="max-length">4000</hint>
</hint-collection>
l 每個model的缺省hints
<default-hints>
<hint name="display-width">150</hint>
</default-hints>
l 一些字段的特殊hints。又分爲兩類: hint-collection 和 hint 。其中,hint-collection是對前述collection的引用,hint是一些簡單的定義。
<hint-collection name="TEXTAREA" />
<hint-collection name="BLOB" />
<hint name="show-time">false</hint>
<hint name="display-width">150</hint>
<hint name="max-length">200</hint>
1.2 文件的生成
該文件是由ServiceBuilder工具產生的。具體在com.liferay.portal.tools. ServiceBuilder中的函數_createModelHintsXML()中實現。
這個方法,是首先讀出原來的文件內容,然後根據新的model List對XML內容進行修改。缺省情況下,自定義portlet中新建的model,添加到xml文件中沒有任何hint信息。
這裏有一個問題,根據需要,如果手工需要修改該文件,但下次重新ant build-service的時候,我們手工修改的內容是不是會被覆蓋掉呢?根據前面對代碼的閱讀,我的初步判斷是不會。同時,我又做了一下測試,驗證了我的猜測。
1.3 文件的調用關係
在文件中如何應該該文件,也就是這個文件究竟有什麼用?這是我們研究這個東西的目標。
文件的應用,主要是以下幾個環節
1.3.1 文件portal.properties中定義
##
## Model Hints
##
#
# Input a list of comma delimited model hints configurations.
#
model.hints.configs=META-INF/portal-model-hints.xml,META-INF/ext-model-hints.xml
1.3.2 文件com.liferay.portal.util.PropsUtil中定義變量
// Model Hints
public static final String MODEL_HINTS_CONFIGS = "model.hints.configs";
1.3.3 文件com.liferay.portal.model.ModelHintsUtil中讀取文件內容
1.3.3.1 代碼分析
在構造函數中,核心代碼
private ModelHintsUtil() {
_hintCollections = CollectionFactory.getHashMap();
_defaultHints = CollectionFactory.getHashMap();
_modelFields = CollectionFactory.getHashMap();
ClassLoader classLoader = getClass().getClassLoader();
String[] configs = StringUtil.split(
PropsUtil.get(PropsUtil.MODEL_HINTS_CONFIGS));
for (int i = 0; i < configs.length; i++) {
_read(classLoader, configs[i]);
}
}
核心代碼調用的是 函數_read(ClassLoader classLoader, String source),依次在分析一個model-hints.xml文件的內容。核心代碼分析
String xml = StringUtil.read(classLoader, source);
首先讀取hint-collection部分,並保存在全局Map _hintCollections中
然後依次讀取每一個model,並將每個model的default-hints以model的name爲key,保存在Map_defaultHints中。然後在_modelFields中保存所有的field的定義,每個model的所有field放在一個Map中,並將該Map以model的name爲key,保存在Map _modelFields中。
數據的保存,基本上等同於原來XML文件的格式,採用Map作爲容器進行存放。記住三個關鍵的全局Map變量:
private Map _hintCollections;
private Map _defaultHints;
private Map _modelFields;
1.3.3.2 ModelHintsUtil的一些可用的方法
Map getDefaultHints(String model)
Element getFieldsEl(String model, String field)
String getType(String model, String field)
Map getHints(String model, String field)
1.3.3.3 檢查哪些代碼使用了ModelHintsUtil
結果發現只有一個java文件,那就是com.liferay.portal.tools. ServiceBuilder。呵呵,進入了循環。
我初步得出的結論是:model-hints.xml文件在運行過程中,好像沒什麼用。爲了檢驗這一點,我嘗試在運行環境中,把portal-ext.properties中的變量model.hints.configs設置爲非法值,然後嘗試運行liferay,看看有沒有異常。將變量內容修改爲:
model.hints.configs=META-INF/portal-model-hints-no.xml,META-INF/ext-model-hints-no.xml
重新啓動liferay,簡單嘗試了幾個功能。登錄時沒有問題,但在創建文件時發現了問題,form的input對象沒有列出來;創建留言薄分類的時候,也是同樣的問題。
1.4 JSP對文件model-hints.xml的調用情況
因爲在java代碼中沒有發現問題,但是在執行的時候,一些form的input的顯示出現了問題,可以認爲,model-hints.xml應該是影響form端的ui的。
在jsp中,以html/portlet/message_boards/edit_category.jsp 爲例,input的代碼如下,
<liferay-ui:input-field model="<%= MBCategory.class %>" bean="<%= category %>" field="description" />
在文件liferay-ui.tld中,input-field的定義爲
<tag>
<name>input-field</name>
<tagclass>com.liferay.taglib.ui.InputFieldTag</tagclass>
<bodycontent>JSP</bodycontent>
</tag>
檢查文件com.liferay.taglib.ui.InputFieldTag.java,發現其實際調用的應該是JSP文件/html/taglib/ui/input_field/page.jsp。
檢查這個JSP的內容,原來在這裏,核心代碼如下:
String type = ModelHintsUtil.getType(model, field);
Map hints = ModelHintsUtil.getHints(model, field);
displayHeight = GetterUtil.getString((String)hints.get("display-height"), displayHeight);
displayWidth = GetterUtil.getString((String)hints.get("display-width"), displayWidth);
maxLength = GetterUtil.getString((String)hints.get("max-length"), maxLength);
upperCase = GetterUtil.getBoolean((String)hints.get("upper-case"), upperCase);
checkTab = GetterUtil.getBoolean((String)hints.get("check-tab"), checkTab);
<textarea class="form-text" <%= disabled ? "disabled" : "" %> id="<%= namespace %><%= field %>" name="<%= fieldParam %>" style="height: <%= displayHeight %>px; width: <%= displayWidth %>px;" wrap="soft" onKeyDown="<%= checkTab ? "checkTab(this); " : "" %> disableEsc();" onKeyPress="checkMaxLength(this, <%= maxLength %>);"><%= value %></textarea>
1.5 結論:model-hints.xm文件的作用
這些文件是用來在JSP中顯示和處理Form的Input參數的。在JSP中,使用<liferay-ui:input-field 的方法來輸出input等,底層代碼需要調用ModelHintsUtil獲取該field的相關信息,並調整顯示情況,以及一些js的處理。詳細使用方法,需要查閱/html/taglib/ui/下面的這些文件的代碼。