【问题标题】:Spring MVC + Hibernate: Partial model update from browserSpring MVC + Hibernate:来自浏览器的部分模型更新
【发布时间】:2012-12-10 00:00:45
【问题描述】:

当只显示 Spring MVC 模型 bean 的一部分时,有没有办法只在模型中更新从浏览器返回的内容?

假设我们有一个 User 类(当然,在这个例子中只有公共属性):

public class User {
  public String firstName;
  public String lastName;
  public String email;
  public Date subscriptionExpiration;
}

现在我将前三个属性显示为 JSP 中的输入字段,并希望相应地更新数据库中的对象。应该只更新这 3 个参数,而不是第四个。实现此目的的一种方法是

@RequestMapping("/user/{userId}", method=RequestMethod.POST)
public String saveChanges(@PathVariable userId, User user, Model model) {
  User oldUser = User.loadFromDB(userId);
  oldUser.firstName = user.firstName;
  oldUser.lastName = user.lastName;
  oldUser.email = user.email;
  oldUser.saveToDB();

  model.addAttribute("user", oldUser);
}

但这意味着硬编码所有可能改变的属性,我不太喜欢。

有没有办法根据允许用户更改的内容来确定要更新哪些字段?该机制应该比仅仅假设请求参数中的所有内容都可以更改更智能,否则任何精明的用户都可以手动将其他字段注入请求中。

在我看来,使用 @Entity(dynamicUpdate=true) 也不能解决问题,因为我没有将整个 User 对象返回到请求中,这样做会带来许多安全漏洞。

我错过了 Spring 中的一个不错的功能,还是有任何其他方法可以从概念上解决这个问题?非常感谢任何提示!

【问题讨论】:

    标签: java spring hibernate spring-mvc


    【解决方案1】:

    我有同样的问题,最后通过添加一个类型转换器来解决它。

    public class AbstractDocumentConverter implements Converter<String, AbstractDocument> {
    
        private AbstractDocumentRepository abstractDocumentRepository;
    
        public AbstractDocumentConverter(AbstractDocumentRepository abstractDocumentRepository) {
            this.abstractDocumentRepository = abstractDocumentRepository;
        }
    
        @Override
        public AbstractDocument convert(String id) {
            return abstractDocumentRepository.findOne(id);
        }
    }
    

    我使用 mongodb,AbstractDocument 是我所有文档的超类,在控制器中我添加了 @ModelAttribute("id") 。

    @RequestMapping("save")
    public String save(@ModelAttribute("id") SportGame game) {
        sportGameService.save(game);
        return "redirect:/game/list";
    }
    

    它将首先将id转换为模型(在我的转换器中,它通过id从db中找到一个),然后从请求参数中填充模型字段。

    【讨论】:

      【解决方案2】:

      您正在寻找的好功能是@ModelAttribute。我假设您的表单也会发布用户 ID。

      public class UserController {
      
          @ModelAttribute
          public User getUser(@RequestParam(value = "id", required = false) Long id) {
              return User.loadFromDB(id);
          }
      
          @RequestMapping("/user/{id}", method=RequestMethod.POST)
          public String saveChanges(@ModelAttribute User user, BindingResult bindingResult, Model model) {
      
              if (bindingResult.hasErrors()) {
                  // return ...
              }
      
              //  model.asMap().clear();
      
              user.saveToDB();
              // return ...
          }
      }
      

      【讨论】:

        【解决方案3】:

        一种选择是利用表单中的隐藏字段。一个有缺点的选项,但它适用于某些情况

        【讨论】:

          【解决方案4】:

          您可以先从数据库中读取对象,然后再绑定请求。你可以在FuWeSta-Sample找到一个例子。

          它使用helper-bean,它必须由 Spring 初始化。

          【讨论】:

            【解决方案5】:

            我觉得方法

            BeanUtils.copyProperties(Object source, Object target, String[] ignoreProperties) 
            

            做你想做的事。它将所有属性从一个对象复制到另一个对象,而不会触及String[] ignoreProperties 中定义的属性。

            将给定源 bean 的属性值复制到给定目标 bean 中,忽略给定的“ignoreProperties”。

            注意:源类和目标类不必匹配,甚至不必相互派生,只要属性匹配即可。源 bean 公开但目标 bean 未公开的任何 bean 属性都将被忽略。

            这只是一种方便的方法。对于更复杂的传输需求,请考虑使用完整的 BeanWrapper。

            API Documentation

            【讨论】:

            • 暂时我做过这样的事情;我在字段上使用自定义注释来控制它们是否会被更新,然后解析它们以提供一个 ignoreProperties 列表。它运作良好,但我想避免手动定义它。感谢您的意见!
            【解决方案6】:

            请参阅this question 了解如何使用@InitBinder 来允许/防止某些模型字段被Spring 绑定以请求参数。这样可以确保subscriptionExpiration 不能通过注入请求参数来修改。

            请参阅the documentation,了解如何在方法和方法参数上使用@ModelAttribute 注释从数据库加载用户并将其添加到模型中,然后再调用@RequestMapping 方法,并使用请求填充此用户调用@RequestMapping 方法时的参数。这允许从数据库中获取用户并让 Spring 使用来自请求的 ne 值填充它。您所要做的就是验证用户的新状态并将其保存到数据库中。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-07-25
              相关资源
              最近更新 更多