3.5.13. 插件工厂
插件工厂机制扩展了标准组件的创建过程,允许在 FieldGroup、 Table 和 DataGrid 中创建不同的编辑字段。这意味着应用程序组件或应用程序项目本身可以提供自定义策略,以创建非标准的组件或支持自定义数据类型。
该机制的入口点是 UiComponentsGenerator.generate(ComponentGenerationContext)
方法。其工作原理如下:
-
尝试查找
ComponentGenerationStrategy
实现。如果找到至少一种策略,那么:-
根据
org.springframework.core.Ordered
接口遍历策略。 -
返回第一个创建的非
null
组件。
-
ComponentGenerationStrategy
实现用于创建 UI 组件。项目可以包含任意数量的此类策略。
ComponentGenerationContext
是一个类,该类存储创建组件时可以使用的以下信息:
-
metaClass
- 定义为其创建组件的实体。 -
property
- 定义为其创建组件的实体属性。 -
datasource
- 数据源。 -
optionsDatasource
- 可用于显示选项列表的数据源。 -
valueSource
- 可用于创建组件的值来源。 -
options
- 可用于显示选项的选项对象。 -
xmlDescriptor
- 在组件以声明的方式在 XML 描述中定义时,包含附加信息的 XML 描述。 -
componentClass
- 要创建的组件的类型。例如,FieldGroup
、Table
、DataGrid
。
有两种内置组件策略:
-
DefaultComponentGenerationStrategy
- 用于根据给定的ComponentGenerationContext
对象创建组件。顺序值为ComponentGenerationStrategy.LOWEST_PLATFORM_PRECEDENCE
(1000)。 -
DataGridEditorComponentGenerationStrategy
- 用于根据给定的ComponentGenerationContext
对象为数据网格编辑器创建组件。顺序值为ComponentGenerationStrategy.HIGHEST_PLATFORM_PRECEDENCE + 30
(130)。
以下示例展示如何替换为特定实体的某个属性 FieldGroup
组件的默认生成过程。
import com.company.sales.entity.Order;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.gui.UiComponents;
import com.haulmont.cuba.gui.components.*;
import com.haulmont.cuba.gui.components.data.ValueSource;
import org.springframework.core.Ordered;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.sql.Date;
@org.springframework.stereotype.Component(SalesComponentGenerationStrategy.NAME)
public class SalesComponentGenerationStrategy implements ComponentGenerationStrategy, Ordered {
public static final String NAME = "sales_SalesComponentGenerationStrategy";
@Inject
private UiComponents uiComponents;
@Inject
private Metadata metadata;
@Nullable
@Override
public Component createComponent(ComponentGenerationContext context) {
String property = context.getProperty();
MetaClass orderMetaClass = metadata.getClassNN(Order.class);
// Check the specific field of the Order entity
// and that the component is created for the FieldGroup component
if (orderMetaClass.equals(context.getMetaClass())
&& "date".equals(property)
&& context.getComponentClass() != null
&& FieldGroup.class.isAssignableFrom(context.getComponentClass())) {
DatePicker<Date> datePicker = uiComponents.create(DatePicker.TYPE_DATE);
ValueSource valueSource = context.getValueSource();
if (valueSource != null) {
//noinspection unchecked
datePicker.setValueSource(valueSource);
}
return datePicker;
}
return null;
}
@Override
public int getOrder() {
return 50;
}
}
请注意,在更改返回的组件类型时,覆盖现有的生成策略可能会产生错误,因为界面控制器中的代码可能依赖于特定的组件类型。 例如,在使用上述策略的情况下,以下注入将产生异常:
如果尝试打开此类界面,则会出现以下异常: IllegalArgumentException: Can not set com.haulmont.cuba.gui.components.DateField field com.company.sales.web.order.OrderEdit.dateField to com.haulmont.cuba.web.gui.components.WebDatePicker |
以下示例展示如何为特定的 datatype 定义 ComponentGenerationStrategy
。
import com.company.colordatatype.datatypes.ColorDatatype;
import com.haulmont.chile.core.datatypes.Datatype;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.chile.core.model.MetaPropertyPath;
import com.haulmont.chile.core.model.Range;
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesUtils;
import com.haulmont.cuba.gui.UiComponents;
import com.haulmont.cuba.gui.components.ColorPicker;
import com.haulmont.cuba.gui.components.Component;
import com.haulmont.cuba.gui.components.ComponentGenerationContext;
import com.haulmont.cuba.gui.components.ComponentGenerationStrategy;
import com.haulmont.cuba.gui.components.data.ValueSource;
import org.springframework.core.annotation.Order;
import javax.annotation.Nullable;
import javax.inject.Inject;
@Order(100)
@org.springframework.stereotype.Component(ColorComponentGenerationStrategy.NAME)
public class ColorComponentGenerationStrategy implements ComponentGenerationStrategy {
public static final String NAME = "colordatatype_ColorComponentGenerationStrategy";
@Inject
private UiComponents uiComponents;
@Nullable
@Override
public Component createComponent(ComponentGenerationContext context) {
String property = context.getProperty();
MetaPropertyPath mpp = resolveMetaPropertyPath(context.getMetaClass(), property);
if (mpp != null) {
Range mppRange = mpp.getRange();
if (mppRange.isDatatype()
&& ((Datatype) mppRange.asDatatype()) instanceof ColorDatatype) {
ColorPicker colorPicker = uiComponents.create(ColorPicker.class);
colorPicker.setDefaultCaptionEnabled(true);
ValueSource valueSource = context.getValueSource();
if (valueSource != null) {
//noinspection unchecked
colorPicker.setValueSource(valueSource);
}
return colorPicker;
}
}
return null;
}
protected MetaPropertyPath resolveMetaPropertyPath(MetaClass metaClass, String property) {
MetaPropertyPath mpp = metaClass.getPropertyPath(property);
if (mpp == null && DynamicAttributesUtils.isDynamicAttribute(property)) {
mpp = DynamicAttributesUtils.getMetaPropertyPath(metaClass, property);
}
return mpp;
}
}