Spring MVC + Hibernate:来自浏览器的部分模型更新

时间:2012-12-22 20:56:38

标签: java spring hibernate spring-mvc

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

假设我们有一个User类(当然这只是公共属性):

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

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

@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中错过了一个不错的功能,还是有其他方法可以从概念上解决这个问题?任何提示都非常感谢!

6 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:2)

我认为方法

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

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

  

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

     

注意:只要属性匹配,源类和目标类就不必相互匹配,甚至不必相互派生。

表示源bean暴露但目标bean不会被忽略的任何bean属性。

     

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

API Documentation

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

一个选项是使用表单中的隐藏字段。一个带退回的选项,但它适用于某些情况

答案 4 :(得分:0)

您正在寻找的好功能是@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 ...
    }
}

答案 5 :(得分:0)

我有同样的问题,最后只需添加类型转换器即可解决。

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中找到一个),然后从请求参数中填充模型字段。