反思是我最好的选择吗?

时间:2011-09-14 15:55:24

标签: java reflection spring-mvc

我们允许用户在我们的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方法中的所有检查的辅助函数也会变得难以处理(并且在创建新的首选项时似乎很容易忘记);同时反射似乎是一个警察。有没有更好的方法来重构这个?

1 个答案:

答案 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");
}