【问题标题】:Spring Data JPA: How to update a model elegantly?Spring Data JPA:如何优雅地更新模型?
【发布时间】:2015-10-24 10:31:22
【问题描述】:
  1. 我的模型是这样的:

    @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
    }
    
  2. 我们通过 http 请求收集表单或移动数据,springmvc 会将这些数据提供给 Model 类用户。

    例如,我有一个这样的请求:

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

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

    @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);
    }
    
  4. 如果我在mysql中有一条id为1919的记录,并且列(id、email、weblik)都有值。

    如你所见,通过 web 或 mobile 传递的用户对象有两个属性

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

    id 和 email 有值,而 weblink 没有。

    所以,如果我执行save方法,列email会更新为xx@google.com,weblik字段也会更新为NULL,但是我不想更新这个字段,我只是想要更新电子邮件字段。

  5. 我有两种方法可以解决这个问题,但都不是优雅的。

    5.1 先加载用户对象并更新

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

    5.2 使用@DynamicUpdate,但它不起作用。

    有没有其他方法可以更新用户模型并且不做一些额外的工作。

    提前致谢。

【问题讨论】:

标签: spring spring-mvc spring-boot spring-data spring-data-jpa


【解决方案1】:

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

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

根据reference documentation调用此方法时发生以下步骤:

  1. 需要获取User 的实例。这基本上需要一个从StringUserConverter 向Spring MVC 注册,以便将从URI 模板中提取的路径段转换为User。如果你是例如使用 Spring Data 并启用其reference documentation 中所述的 Web 支持,这将开箱即用。
  2. 获取现有实例后,请求数据将绑定到现有对象。
  3. 绑定的对象将被交给方法。

其他提示

  • 不要使用GET 作为更新的HTTP 方法。 GET 被定义为安全操作(无副作用),而更新则不是。 PATCH 是正确的方法,因为它被定义为允许对现有资源进行部分更新。
  • 要将表单数据提交到PUTPATCH 请求中,您需要按照here 的说明向应用程序注册HttpPutFormContentFilter。我提交了issue with Spring Boot 以默认注册。

【讨论】:

  • @oliver-gierke 我得到了第 1 步的工作,但我不能让第 2 步工作,我的意思是对象是从作为参数传递给方法的 db 获得的,但是请求似乎被忽略了。根据我的理解,我发送到请求正文中的任何内容都应该应用到获取的对象中。有什么建议?你有一个可行的例子来看看吗?谢谢!
  • 算了,我发现了问题。 HttpPutFormContentFilter 没有被创建,因为我正在扩展 WebMvcConfigurerAdapter,这会阻止 WebMvcAutoConfiguration 的实例化。现在我还有一个问题,为什么HttpPutFormContentFilter只在内容类型为application/x-www-form-urlencoded时才应用?是否可以应用相同的过程但使用 application/json 内容类型?谢谢!
  • @MauroMonti 你有没有找到一种优雅的方式来为 JSON 和/或 XML 实现这个?
  • 无论如何要从 authenticationObject 中获取 Id 以进行实例化?目前在您发布的解决方案中,它要求在"/users/{user}" 中发送userId。我需要这个,因为当 id 为 1 的用户登录时,我只希望他们转到页面 /user 而不是 /user/1。当他们想要更新某些内容时,他们仍然会转到 PATCH /user 而不是 PATCH /user/1
【解决方案2】:

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

而在我之前的项目中,我的解决方案是:
1、创建抽象类实现JpaRepository,实现save()功能。
2. 在保存函数中,从数据库中获取实体。它不存在,只是保存它。否则,使用反射从更新的实体中获取所有 NOT NULL 字段,并从 DB 中设置为实体。 (和你做的很相似,但我是为所有的保存功能做的)

【讨论】:

    猜你喜欢
    • 2017-02-06
    • 2018-11-09
    • 1970-01-01
    • 2012-08-06
    • 1970-01-01
    • 2023-03-29
    • 2019-05-18
    • 2018-09-23
    • 1970-01-01
    相关资源
    最近更新 更多