WebObjects/Web 应用程序/开发/通用最佳实践
困扰新 WebObjects 开发人员的一个更严重的问题源于在 appendToResponse 中创建和发送一个 WOComponent,然后在随后的 takeValuesFromRequest 和 invokeAction 方法在该页面上完成之前更改该组件的结构。
这样做会混淆 WO 在 takeValuesFromRequest 或 invokeAction 中引用该页面时的解释。结果会让你感觉你的 WOComponent 患上了精神分裂症。如果它在 takeValuesFromRequest 期间变得混乱,它将从表单上的一个或多个字段中获取值,并将它们放入相应类文件中的不相关实例变量中。如果它在 invokeAction 期间变得混乱,它将激活与你点击的 WOSubmitButton 或 WOHyperlink 绑定的动作方法无关的动作方法。
简而言之,如果你的页面开始表现出精神分裂症的行为,这是我第一个要检查的地方。那么,到底是什么问题呢?
从你执行 appendToResponse() 的那一刻起,你必须确保用来创建作为响应发送出去的 HTML 结构的所有对象,都不会以任何可能导致该 HTML 结构(页面模板)在随后的 takeValuesFromRequest() 和 invokeAction() 方法完成之前发生变化的方式发生变化。特别是,如果 WOConditionals 依赖的任何布尔值发生变化,如果 WORepetitions 中使用的任何数组大小发生变化,那么你就创建了一个问题,其表现形式通常很难追踪。
当你执行 appendToResponse 时,WO 使用你的 WOComponents、子组件和 WOElements 来创建一个对象的层次结构(一个对象图),然后它 "遍历" 该层次结构以生成 HTML。当 takeValuesFromRequest 和 invokeAction 方法执行时,WO 会重新创建此模板并重新 "遍历" 它,以确定哪些对象接收返回的值以及哪个对象负责调用动作。如果你的对象图的任何更改会导致该模板结构在 appendToResponse 与相应的 takeValuesFromRequest 和 invokeAction 之间发生变化,那么 WO 会迷路,可能会在你的表单对象中放置错误的值,并确定是错误的元素(例如,WORadioButton)导致了动作。
这是一个常见且严重的错误。
如果你有 WOConditionals,最安全的做法是将它们绑定到类文件中的布尔值,你只在 appendToResponse 中更改这些布尔值,在它调用 super.appendToResponse 之前。如果这很困难,请在你的程序中使用任何自然的逻辑,但在 super.appendToResponse 之前,放置一个布尔值(你将 WOConditional 绑定到它),以反映该逻辑,并且只在该方法中的那个点相应地更改布尔值。
如果你有 WORepetitions,请确认你的代码不会在激活 super.appendToResponse 和完成该页面的相应 invokeAction 之间更改这些数组的大小或它们大小依赖的索引。
有关此过程及其后果的更深入解释,请参阅[1]。特别注意最后一段以及下一頁[2]。在这最后一頁,请特别注意倒数第二段。
不要使用
MyNewPage nextPage = (MyNewPage)pageWithName("MyNewPage");
更喜欢这种形式
MyNewPage nextPage = (MyNewPage)pageWithName(MyNewPage.class.getName());
class.getName() 允许 Eclipse 进行正确的重构,你可以右键单击=>引用=>工作空间你的类,并真正找到所有引用,而不是仅仅拥有字符串引用。它具有的另一个优点是,如果你有两个同名但位于不同包中的页面,这可以避免混淆。如果你只使用 pageWithName("MyNewPage";),WO 可能返回错误的一个。虽然是微小的变化,但确实有很好的好处。
如果你使用 1.5,你可以使用 1.5 的变体
@SuppressWarnings("unchecked") public <T extends WOComponent> T pageWithName(Class<T> componentClass) { return (T) super.pageWithName(componentClass.getName()); }
这将移除一个强制转换
MyNewPage nextPage = pageWithName(MyNewPage.class);
KeyValueCoding(也称为 KVC)倾向于鼓励使用类似于这样的结构
website.addObjectToBothSidesOfRelationshipWithKey(newFolder, “folders”);
这会使代码中充斥着硬编码的字符串。更改属性名称会破坏代码,不会发出编译警告。如果你使用 EOGenerator 为名称生成常量
public static final String FOLDERS = “folders”;
你可以在硬编码的字符串中使用它们,并在更改影响代码时获得错误
website.addObjectToBothSidesOfRelationshipWithKey(newFolder, FOLDERS);
执行此操作的 EOGenerator 模板(片段)
public static final String ENTITY_NAME = "<$name$>"; <$foreach propertyName classPropertyNames.@reversedArray do$> public static final String <$propertyName.uppercaseString$> = "<$propertyName$>";<$endforeach do$>
- 这没有解决在 wod 文件中绑定中使用属性名称时的相关问题
- 这在(不可否认的罕见)情况下不起作用,即一个类实现多个实体。EOGenerator 假设一个实体 == 一个类。因此,MyEO.ENTITY_NAME 将返回最后一个生成的实体的名称。
有关更多类似技巧,请参阅EOGenerator 页面。