java Spring MVC 表单支持对象树初始化的最佳实践
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/378066/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best Practice for Spring MVC form-backing object tree initialization
提问by Jacob Mattison
If I have a form-backing object that has a complicated object tree -- say a Person that has a Contact Info object that has an Address object that has a bunch of Strings -- it seems that the object needs to be fully populated with component objects before I can bind to it. So if I'm creating a new Person, I need to make sure it has all the component objects populated off the bat, and if I'm retrieving a Person from the database, I need to make sure that any objects that aren't populated from the database get populated with empty objects.
如果我有一个具有复杂对象树的表单支持对象 - 比如说一个 Person 有一个 Contact Info 对象,该对象有一个 Address 对象,该对象有一堆字符串 - 似乎该对象需要完全填充组件对象之前我可以绑定到它。因此,如果我正在创建一个新的 Person,我需要确保它具有立即填充的所有组件对象,并且如果我从数据库中检索一个 Person,我需要确保任何不是从数据库填充得到填充空对象。
First question, of course -- am I correct in my assumptions above? It does seem that if I try to bind to person.contactInfo.homeAddress.street and there is no ContactInfo, I get a null pointer exception.
当然,第一个问题——我的上述假设是否正确?似乎如果我尝试绑定到 person.contactInfo.homeAddress.street 并且没有 ContactInfo,我会得到一个空指针异常。
Second, what's the best way to initialize my object. I can think of a couple of approaches. One is to initialize all member objects at declaration:
其次,初始化我的对象的最佳方法是什么。我可以想到几种方法。一种是在声明时初始化所有成员对象:
public class Person {
String name;
ContactInfo contactInfo = new ContactInfo();
//getters, setters, etc.
}
public class ContactInfo {
String phone;
Address homeAddress = new Address();
}
and so forth.
等等。
Another approach is to have a PersonFactory that initializes everything (or to have a factory method Person.getInstance that initializes everything).
另一种方法是拥有一个初始化所有内容的 PersonFactory(或拥有一个初始化所有内容的工厂方法 Person.getInstance)。
In the case of retrieving a Person from the database, the first approach will solve the issue (i.e. if this particular person doesn't have an address in the database, the object will still have an Address), but this will mean creating each object twice. Not sure how to handle this otherwise, except to make the DAO explicitly populate everything even if nothing has been retrieved from the database. Or to give the factory a method to go through the object and "fill in" anything that's missing.
在从数据库中检索 Person 的情况下,第一种方法将解决该问题(即,如果此特定人在数据库中没有地址,则该对象仍将有一个地址),但这将意味着创建每个对象两次。不知道如何以其他方式处理这个问题,除了使 DAO 显式填充所有内容,即使没有从数据库中检索到任何内容。或者给工厂一个方法来遍历对象并“填充”缺少的任何东西。
Suggestions?
建议?
采纳答案by Jacob Mattison
Call it overkill if you like, but what we actually ended up doing was to create a generic factory that will take any object and use reflection to (recursively) find all the null properties and instantiate an object of the correct type. I did this using Apache Commons BeanUtils.
如果您愿意,可以称之为矫枉过正,但我们实际上最终做的是创建一个通用工厂,它将接受任何对象并使用反射来(递归地)找到所有空属性并实例化正确类型的对象。我使用 Apache Commons BeanUtils 做到了这一点。
This way you can take an object that you may have gotten from various sources (a DAO, deserialization from XML, whatever), pass it through this factory, and use it as a form-backing object without worrying that something you need for binding may be null.
通过这种方式,您可以获取可能从各种来源(DAO、从 XML 反序列化,等等)获得的对象,将其传递给这个工厂,并将其用作表单支持对象,而不必担心绑定所需的东西可能会为空。
Admittedly, this means instantiating properties that we may not need for a given form, but in our case that doesn't typically apply.
诚然,这意味着实例化我们可能不需要的属性,但在我们的情况下通常不适用。
回答by Nick Holt
I would generally make sure objects are fully initialized - it makes using the object that much simplier and avoids you scattering null checks throughout your code.
我通常会确保对象已完全初始化 - 它使使用对象变得更加简单,并避免您在整个代码中散布空检查。
In the case you give here I'd probably put the initialization in the getter so the child object is only instantiated when it's actually going to be used, ie: when the getter is called and then only if it's null.
在你在这里给出的情况下,我可能会将初始化放在 getter 中,因此子对象仅在实际使用时才会实例化,即:当 getter 被调用时,然后仅当它为 null 时。
In terms of loading from the database with one-to-one relationships I'd normally do the join and load the lot. The performance impact is typically minimal but you should be aware that there may be one.
在从具有一对一关系的数据库加载方面,我通常会进行连接并加载大量内容。性能影响通常很小,但您应该意识到可能会有影响。
When it comes to one-to-many relationships I normally go for lazy loading. Hibernate will take of this for you, but if you're rolling your own then you just need a custom implementation of List that calls the appropriate DAO when any of the methods relating to its contents are called.
当谈到一对多的关系时,我通常会选择延迟加载。Hibernate 会为您解决这个问题,但是如果您自己滚动,那么您只需要一个 List 的自定义实现,当调用与其内容相关的任何方法时,它会调用适当的 DAO。
The one exception to this behavior with one-to-many relationships is when you've got a list of parent objects that you intend to iterate over and for each parent you want to iterate over its children. Obviously the performance would suck because you'd be making a n + 1 calls to the DB when you could actually do it with 2 calls.
这种具有一对多关系的行为的一个例外是,当您有一个要迭代的父对象列表,并且对于每个要迭代其子对象的父对象时。显然,性能会很糟糕,因为当您实际上可以通过 2 次调用来完成时,您将对数据库进行 + 1 次调用。
回答by bpapa
I've gone with the Factory method approach (not a fan of using a seperate class for it, to me it makes more sense to have it in a static method so it's all in one place). I have something like -
我已经采用了工厂方法方法(不喜欢为它使用单独的类,对我来说,将它放在静态方法中更有意义,所以它都在一个地方)。我有类似的东西 -
public static Person getInstanceForContactInfoForm() {
ContactInfo contactInfo = ContactInfo.getInstanceForContactInfoForm();
Person person = new Person(contactInfo);
// set whatever other properties you need for Person
// just enough to 1-render the form and 2-avoid any exceptions
return person;
}
If I'm loading the Person from the database, I have a method in the Person class called something like "initalizeForContactInfoForm" or something. After loading the Person from the database, I'll call this method in the Service layer in the method that is called by the Spring MVC method which returns the Form Backing Object.
如果我从数据库加载 Person,我在 Person 类中有一个方法,称为“initalizeForContactInfoForm”之类的东西。从数据库加载Person 后,我将在返回Form Backing Object 的Spring MVC 方法调用的方法中的Service 层中调用此方法。
I don't think this is a really a convention, it's just an approach I cooked up on my own. I don't really see what any drawbacks are so if somebody disagrees please let me know...
我不认为这是一个真正的约定,这只是我自己制定的一种方法。我真的不明白有什么缺点所以如果有人不同意请告诉我...
回答by Olivier
I guess you are talking about something like < form:input path="person.contactInfo.homeAddress.street"/>?
Not clear for me but assuming i'm right :) :
我猜你在谈论类似的事情< form:input path="person.contactInfo.homeAddress.street"/>?我不清楚,但假设我是对的:):
1) Yes, When you write person.contactInfo.homeAddress.street , read person.getContactInfo().getHomeAddress().getStreet(). If ContactInfo or HomeAddress or Street objects are null, invocation of one of their method raises a NullPointException.
1)是的,当你写person.contactInfo.homeAddress.street ,读person.getContactInfo().getHomeAddress().getStreet()。如果 ContactInfo 或 HomeAddress 或 Street 对象为空,则调用它们的方法之一会引发 NullPointException。
2)I usually initializes member objects at declaration, just like in code snippet. Don't see the benefit of factory class to do the job if initialization values are inconditionnal. I don't clearly see the problem where you are forced to create a Person twice... but i may be tired ;)
2)我通常在声明时初始化成员对象,就像在代码片段中一样。如果初始化值是无条件的,则看不到工厂类完成这项工作的好处。我没有清楚地看到你被迫两次创建一个人的问题......但我可能很累;)

