反射是我最好的选择吗?



我们允许用户在我们的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");
}

相关内容

  • 没有找到相关文章

最新更新