我们允许用户在我们的web应用程序中设置一些偏好。当他们登录到某些网站时,他们被允许做/看到与他们在另一个网站时不同的屏幕。我们的要求之一是,我们隐藏在页面上的首选项,他们不能在当前登录的网站访问。目前我们正在使用Spring MVC来处理这些请求。
下面是我们的POJO的一个简化示例:
public class Preferences {
boolean prefA; //Valid when can do A
String prefB; //Valid when can do B
Integer prefC; //Valid when can do C
....
Long prefZ; //Valid when can do Z
}
控制器代码:
@RequestMapping(method = RequestMethod.POST, value = "preferences.xhtml")
public ModelAndView updateRequestPreferences(@ModelAttribute(USER_PREFERENCES) final Preference preferences, final BindingResult results)
{
return updatePreferences(preferences, results);
}
当前updatePreferences做反射,并确保值在持久化输入首选项之前不为空——这是由于Spring MVC创建了preferences的新实例,然后用UI上的内容填充值。
可以在首选项的setter中执行以下操作:
public void setPreferences(Preferences preferences) {
if (preferences.getPrefA() != null) {
this.preferences.setPrefA(preferences.getPrefA());
}
if (preferences.getPrefB() != null) {
this.preferences.setPrefB(preferences.getPrefB());
}
...
if (preferences.getPrefZ() != null) {
this.preferences.setPrefZ(preferences.getPrefZ());
}
}
即使在setter方法中为所有检查提供辅助函数也会变得笨拙(并且在创建新首选项时似乎很容易忘记);同时,反思似乎是一种逃避。有没有更好的方法来重构它?
您可以将Spring MVC配置为填充已有对象的字段,而不是创建新对象。
例如,您可以使用@SessionAttributes(USER_PREFERENCES)
,以便在呈现表单和处理其提交之间的会话中存储Preferences
的实例。
另一种方法是从数据库中加载新的Preferences
实例作为隐式模型属性:
@ModelAttribute(USER_PREFERENCES)
public Preferences loadPreferences(@RequestParam("key") String key) {
return loadPreferencesByKey(key);
}
请注意,在所有情况下(您的原始方法也需要它),您需要在@InitBinder
方法中指定一组允许的字段,以防止恶意用户修改未在表单中呈现的字段:
@InitBinder(USER_PREFERENCES)
public void initBinder(WebDataBinder b) {
b.setAllowedFields("prefA", "prefB");
}