Spring Data JPA:如何优雅地更新模型?

10
  1. 我的模型长这样:

  2. @Entity
    @Table(name = "user")
    public class User {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        @Column(name="email")
        private String email;
    
        @Column(name = "weblink")
        private String webLink;
    
        //getter & setter
    }
    
  3. 我们通过http请求收集表单或移动端数据,springmvc将这些数据制作成模型(如用户模型)。

    例如,我有一个请求如下:

    http://localhost:8080/update?id=1919&email=xx@google.com

  4. 在控制器中,请求URL及其参数将自动转换为User对象。

  5. @RequestMapping(method = RequestMethod.GET, value = "/update0")
    public User update(@ModelAttribute("User") User user){
    
        System.out.println(user.getId());
        System.out.println(user.getEmail());
        System.out.println(user.getWebLink());
    
        return userRepository.save(test);
    }
    
  6. 假设我在mysql中有一条id为1919的记录,且(id, email, weblik)这些列都有值。

    正如你所看到的,通过web或移动端传递的用户对象具有两个属性

    http://localhost:8080/update?id=1919&email=xx@google.com

    其中id和email具有值,而weblink没有值。

    因此,如果我执行save方法,将会更新email字段的值为xx@google.com,同时将weblink字段更新为NULL,但我并不想更新weblink字段,我只是想更新email字段。

  7. 我有两种方法来解决这个问题,但它们都不够优雅。

    5.1 首先加载用户对象,然后再进行更新

  8. User userExist = userRepository.findOne(user.getId());
    userExist.setEmail(user.getEmail());
    
    //or using 
    //BeanUtil.copyProprty(formDto,modle)
    
    userRepository.save();
    

    我尝试使用@DynamicUpdate来更新用户模型,但它没有起作用。

    是否还有其他方法可以更新用户模型而不需要额外的工作呢?

    谢谢提前。


2个回答

13

最简单的方法是设置一个适当的控制器方法:

@RequestMapping(value = "/users/{user}", method = RequestMethod.PATCH)
public … updateUser(@ModelAttribute User user) { … }

根据参考文档,当调用此方法时,以下步骤会发生:

  1. 需要获取一个User实例。这基本上需要在Spring MVC中注册一个从StringUserConverter,将从URI模板提取的路径段转换为User。如果您例如使用Spring Data并按其参考文档中描述的启用其Web支持,则将直接使用。
  2. 获取现有实例后,将绑定请求数据到现有对象。
  3. 绑定的对象将被传递到该方法中。

附加提示

  • 不要使用GET作为更新的HTTP方法。GET被定义为安全操作(没有副作用),而更新则不是。 PATCH是正确的方法,因为它被定义为允许对现有资源进行部分更新。
  • 要将表单数据提交到PUTPATCH请求中,您需要在应用程序中注册一个HttpPutFormContentFilter,如此处描述。我向Spring Boot提出了一个问题,以默认注册它。

@oliver-gierke,我已经完成了第一步,但是第二步无法实现,我的意思是从数据库中获取的对象作为参数传递到方法中,但请求体似乎被忽略了。据我理解,我发送到请求体中的任何内容都应该应用于获取的对象中。有什么建议吗?您有可供查看的工作示例吗?谢谢! - Mauro Monti
忘了吧,我找到问题了。HttpPutFormContentFilter没有被创建,因为我正在扩展WebMvcConfigurerAdapter,这会阻止WebMvcAutoConfiguration的实例化。现在我有另一个问题,为什么只有在内容类型为application/x-www-form-urlencoded时才应用HttpPutFormContentFilter?是否可能使用application/json内容类型应用相同的过程?谢谢! - Mauro Monti
@MauroMonti,你找到了一种优雅的方法来实现JSON和/或XML吗? - Behrang
有没有办法从authenticationObject中获取Id以进行实例化?目前在您发布的解决方案中,需要将userId发送到"/users/{user}"。我需要这个是因为当Id为1的用户登录时,我只想让他们转到页面/user而不是/user/1。当他们想要更新一些内容时,他们仍然会转到PATCH /user而不是PATCH /user/1 - nissim_dev

0

首先,我需要说@Oliver GierkePatch解决方案真的很棒。

在我的上一个项目中,我的解决方案是:
1. 创建一个抽象类来实现JpaRepository,并实现save()函数。
2. 在保存函数中,从数据库获取实体。如果不存在,就保存它。否则,使用反射从更新的实体中获取所有非空字段,并将其设置到来自数据库的实体中。(这与您所做的类似,但我对所有保存函数都这样做了)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接