MSN群中Jacky Miao问到这个问题。自己也不了解,于是乘此机会读了一下源代码。
本文是从Word中拷贝的,因此没有修改标题编号。
经过检查,在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>
该文件是由ServiceBuilder工具产生的。具体在com.liferay.portal.tools. ServiceBuilder中的函数_createModelHintsXML()中实现。
这个方法,是首先读出原来的文件内容,然后根据新的model List对XML内容进行修改。缺省情况下,自定义portlet中新建的model,添加到xml文件中没有任何hint信息。
这里有一个问题,根据需要,如果手工需要修改该文件,但下次重新ant build-service的时候,我们手工修改的内容是不是会被覆盖掉呢?根据前面对代码的阅读,我的初步判断是不会。同时,我又做了一下测试,验证了我的猜测。
在文件中如何应该该文件,也就是这个文件究竟有什么用?这是我们研究这个东西的目标。
文件的应用,主要是以下几个环节
##
## 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
// Model Hints
public static final String MODEL_HINTS_CONFIGS = "model.hints.configs";
在构造函数中,核心代码
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;
Map getDefaultHints(String model)
Element getFieldsEl(String model, String field)
String getType(String model, String field)
Map getHints(String model, String field)
结果发现只有一个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对象没有列出来;创建留言薄分类的时候,也是同样的问题。
因为在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>
这些文件是用来在JSP中显示和处理Form的Input参数的。在JSP中,使用<liferay-ui:input-field 的方法来输出input等,底层代码需要调用ModelHintsUtil获取该field的相关信息,并调整显示情况,以及一些js的处理。详细使用方法,需要查阅/html/taglib/ui/下面的这些文件的代码。