我们允许用户在我们的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执行反射,并确保在持久保存输入首选项之前该值不为null - 这是由于Spring MVC创建了一个新的Preferences实例,然后使用UI上的内容填充值。 p>
我们可以在首选项的设置器中执行以下操作:
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());
}
}
即使使用setper方法中的所有检查的辅助函数也会变得难以处理(并且在创建新的首选项时似乎很容易忘记);同时反射似乎是一个警察。有没有更好的方法来重构这个?
答案 0 :(得分:1)
您可以将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");
}