我正在将 Tapestry 5.3.6 用于 Web 应用程序,我希望用户使用 Web 表单(立即建议使用beaneditform
)编辑 Java 类(“bean”或 POJO)的实例 - 但是 Java 类要编辑的结构相当复杂。我正在 Tapestry 5 中寻找最简单的方法。
首先,让我们定义一些实用程序类,例如
public class ModelObject {
private URI uri;
private boolean modified;
// the usual constructors, getters and setters ...
}
public class Literal<T> extends ModelObject {
private Class<?> valueClass;
private T value;
public Literal(Class<?> valueClass) {
this.valueClass = valueClass;
}
public Literal(Class<?> valueClass, T value) {
this.valueClass = valueClass;
this.value = value;
}
// the usual getters and setters ...
}
public class Link<T extends ModelObject> extends ModelObject {
private Class<?> targetClass;
private T target;
public Link(Class<?> targetClass) {
this.targetClass = targetClass;
}
public Link(Class<?> targetClass, T target) {
this.targetClass = targetClass;
this.target = target;
}
// the usual getters and setters ...
}
现在您可以创建一些相当复杂的数据结构,例如:
public class HumanBeing extends ModelObject {
private Literal<String> name;
// ... other stuff
public HumanBeing() {
name = new Literal<String>(String.class);
}
// the usual getters and setters ...
}
public class Project extends ModelObject {
private Literal<String> projectName;
private Literal<Date> startDate;
private Literal<Date> endDate;
private Literal<Integer> someCounter;
private Link<HumanBeing> projectLeader;
private Link<HumanBeing> projectManager;
// ... other stuff, including lists of things, that may be Literals or
// Links ... e.g. (ModelObjectList is an enhanced ArrayList that remembers
// the type(s) of the objects it contains - to get around type erasure ...
private ModelObjectList<Link<HumanBeing>> projectMembers;
private ModelObjectList<Link<Project>> relatedProjects;
private ModelObjectList<Literal<String>> projectAliases;
// the usual constructors, getters and setters for all of the above ...
public Project() {
projectName = new Literal<String>(String.class);
startDate = new Literal<Date>(Date.class);
endDate = new Literal<Date>(Date.class);
someCounter = new Literal<Integer>(Integer.class);
projectLeader = new Link<HumanBeing>(HumanBeing.class);
projectManager = new Link<HumanBeing>(HumanBeing.class);
projectMembers = new ModelObjectList<Link<HumanBeing>>(Link.class, HumanBeing.class);
// ... more ...
}
}
如果您指向beaneditform
Project.class 的一个实例,在您必须提供大量自定义强制器、翻译器、值编码器等之前,您不会走得太远 - 然后您仍然会遇到无法使用泛型的问题“贡献”表示胁迫者、翻译者、价值编码者等。
然后我开始编写自己的组件来解决这些问题(例如ModelObjectDisplay
和ModelObjectEdit
),但这需要我了解更多 Tapestry 的精髓,而不是我有时间学习......感觉我可能能够做些什么我想使用标准组件和自由使用“委托”等。谁能看到我可以采取的简单路径?
感谢您阅读本文。
PS:如果您想知道我为什么要这样做,那是因为模型表示来自 RDF 图数据库(又名三重存储)的链接数据 - 我需要记住每一位数据的 URI 以及它是如何关联的(链接)到其他数据位(也欢迎您提出更好的方法:-)
编辑:
@uklance 建议使用显示和编辑块 - 这是我已经尝试过的:
首先,我在 AppPropertyDisplayBlocks.tml 中有以下内容......
<t:block id="literal">
<t:delegate to="literalType" t:value="literalValue" />
</t:block>
<t:block id="link">
<t:delegate to="linkType" t:value="linkValue" />
</t:block>
并在 AppPropertyDisplayBlocks.java ...
public Block getLiteralType() {
Literal<?> literal = (Literal<?>) context.getPropertyValue();
Class<?> valueClass = literal.getValueClass();
if (!AppModule.modelTypes.containsKey(valueClass))
return null;
String blockId = AppModule.modelTypes.get(valueClass);
return resources.getBlock(blockId);
}
public Object getLiteralValue() {
Literal<?> literal = (Literal<?>) context.getPropertyValue();
return literal.getValue();
}
public Block getLinkType() {
Link<?> link = (Link<?>) context.getPropertyValue();
Class<?> targetClass = link.getTargetClass();
if (!AppModule.modelTypes.containsKey(targetClass))
return null;
String blockId = AppModule.modelTypes.get(targetClass);
return resources.getBlock(blockId);
}
public Object getLinkValue() {
Link<?> link = (Link<?>) context.getPropertyValue();
return link.getTarget();
}
AppModule.modelTypes 是从 java 类到 Tapestry 使用的字符串的映射,例如 Link.class -> "link" 和 Literal.class -> "literal" ...在 AppModule 中我有以下代码...
public static void contributeDefaultDataTypeAnalyzer(
MappedConfiguration<Class<?>, String> configuration) {
for (Class<?> type : modelTypes.keySet()) {
String name = modelTypes.get(type);
configuration.add(type, name);
}
}
public static void contributeBeanBlockSource(
Configuration<BeanBlockContribution> configuration) {
// using HashSet removes duplicates ...
for (String name : new HashSet<String>(modelTypes.values())) {
configuration.add(new DisplayBlockContribution(name,
"blocks/AppPropertyDisplayBlocks", name));
configuration.add(new EditBlockContribution(name,
"blocks/AppPropertyEditBlocks", name));
}
}
我对编辑块有类似的代码......但是这些似乎都不起作用 - 我认为是因为原始对象被传递给“委托”而不是被取消引用的对象,该对象是存储在文字中的值或链接指向的对象(嗯...应该是上面的 [Ll]inkTarget,而不是 [Ll]inkValue)。我还经常遇到 Tapestry 找不到合适的“翻译器”、“值编码器”或“强制器”的错误……我有一些时间压力,所以很难通过这些曲折的段落来摆脱困境迷宫 :-)