简体   繁体   English

如何在spring-boot数据休息时在POST json中传递@EmbeddedId

[英]How to pass @EmbeddedId in POST json in spring-boot data rest

I have built a REST API using Spring Boot Data REST. 我使用Spring Boot Data REST构建了一个REST API。 I'm using an embeddedId and have also implemented a BackendIdConverter. 我正在使用embeddedId并且还实现了BackendIdConverter。

Below is my Embeddable class 以下是我的Embeddable类

@Embeddable
public class EmployeeIdentity implements Serializable {
    @NotNull
    @Size(max = 20)
    private String employeeId;

    @NotNull
    @Size(max = 20)
    private String companyId;

    public EmployeeIdentity() {}

    public EmployeeIdentity(String employeeId, String companyId) {
        this.employeeId = employeeId;
        this.companyId = companyId;
    }

    public String getEmployeeId() {
        return employeeId;
    }

    public void setEmployeeId(String employeeId) {
        this.employeeId = employeeId;
    }

    public String getCompanyId() {
        return companyId;
    }

    public void setCompanyId(String companyId) {
        this.companyId = companyId;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        EmployeeIdentity that = (EmployeeIdentity) o;

        if (!employeeId.equals(that.employeeId)) return false;
        return companyId.equals(that.companyId);
    }

    @Override
    public int hashCode() {
        int result = employeeId.hashCode();
        result = 31 * result + companyId.hashCode();
        return result;
    }
}

Here's my Employee model 这是我的员工模型

@Entity
@Table(name = "employees")
public class Employee {

    @EmbeddedId
    private EmployeeIdentity id;

    @NotNull
    @Size(max = 60)
    private String name;

    @NaturalId
    @NotNull
    @Email
    @Size(max = 60)
    private String email;

    @Size(max = 15)
    @Column(name = "phone_number", unique = true)
    private String phoneNumber;

    public Employee() {}

    public Employee(EmployeeIdentity id, String name, String email, String phoneNumber) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.phoneNumber = phoneNumber;
    }

    public EmployeeIdentity getId() {
        return id;
    }

    public void setId(EmployeeIdentity id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }
}

And to have resource links generated properly using my embedded id instead of a qualified class name 并使用我的嵌入式ID而不是限定的类名来正确生成资源链接

@Component
public class EmployeeIdentityIdConverter implements BackendIdConverter {

    @Override
    public Serializable fromRequestId(String id, Class<?> aClass) {
        String[] parts = id.split("_");
        return new EmployeeIdentity(parts[0], parts[1]);
    }

    @Override
    public String toRequestId(Serializable source, Class<?> aClass) {
        EmployeeIdentity id = (EmployeeIdentity) source;
        return String.format("%s_%s", id.getEmployeeId(), id.getCompanyId());
    }

    @Override
    public boolean supports(Class<?> type) {
        return Employee.class.equals(type);
    }
}

And here's my repository code 这是我的存储库代码

@RepositoryRestResource(collectionResourceRel = "employees", path = "employees")
public interface EmployeeRepository extends PagingAndSortingRepository<Employee, EmployeeIdentity> {
}

This works fine with GET requests but I need to be able to POST. 这适用于GET请求,但我需要能够POST。 The first thing I noticed that when I do a POST with the json 当我使用json进行POST时,我注意到的第一件事

{
  "id": {
       "employeeId": "E-267", 
       "companyId": "D-432"
  },
  "name": "Spider Man", 
  "email": "spman@somedomain.com", 
  "phoneNumber": "+91-476253455"
}

This doesn't work. 这不起作用。 EmployeeIdentityIdConverter#fromRequestId throws a null pointer exception because the string parameter is null. EmployeeIdentityIdConverter#fromRequestId抛出空指针异常,因为string参数为null。 So I added a null check and return default EmployeeIdentity when id is null. 所以我添加了一个空检查,并在id为null时返回默认的EmployeeIdentity。 As described by this answer https://stackoverflow.com/a/41061029/4801462 如此答案所述https://stackoverflow.com/a/41061029/4801462

Modified EmployeeIdentityIdConverter#fromRequestId 修改后的EmployeeIdentityIdConverter#fromRequestId

@Override
public Serializable fromRequestId(String id, Class<?> aClass) {
    if (id == null) {
        return new EmployeeIdentity();
    }
    String[] parts = id.split("_");
    return new EmployeeIdentity(parts[0], parts[1]);
}

But this raised another problem. 但这引发了另一个问题。 My implementations for hashCode and equals now through null pointer exceptions since the default constructor was used and the employeeId and companyId are null. 我的hashCode和equals的实现现在通过空指针异常,因为使用了默认构造函数而employeeId和companyId为null。

In an attempt to fix this, I gave default values to employeeId and companyId 为了解决这个问题,我给employeeId和companyId提供了默认值

**Modified Employee#Employee() constructor* **修改后的Employee#Employee()构造函数*

public Employee() {
    this.employeeId = "";
    this.companyId = "";
}

NOTE 注意

I am not even sure of what I was doing above. 我甚至不确定我上面做了什么。 I was just trying to fix the small problems as they occurred. 我只是试图解决发生的小问题。

By the way if you guessed this didn't work then you're right. 顺便说一句,如果你猜对了这不起作用,那么你是对的。 While I didn't get an error and the request was successful, I didn't get the behavior I expected. 虽然我没有收到错误并且请求成功,但我没有得到我期望的行为。 A new entry was created with empty employeeId and companyId. 使用空employeeId和companyId创建了一个新条目。

How do make POST to REST API whose model uses @EmbeddedId with spring boot data rest? 如何使POST为REST API,其模型使用带有Spring引导数据的@EmbeddedId?

Here is an other solution. 这是另一种解决方案。 (Still not perfect though.) (虽然还不完美。)

Expose the id for your Employee class: 公开您的Employee类的id:

@Configuration
  protected class MyRepositoryRestConfigurer implements RepositoryRestConfigurer {

   @Override
   public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
     config.exposeIdsFor(ThemeMessage.class);
   }
}

Add the following line to your converter (during POST requests the id will be null): 将以下行添加到转换器中(在POST请求期间,id将为null):

@Override
public Serializable fromRequestId(String id, Class<?> aClass) {
    if(id==null) {
      return null;
    }
    String[] parts = id.split("_");
    return new EmployeeIdentity(parts[0], parts[1]);
}

The following POST request then will work: 然后,以下POST请求将起作用:

{
  "id": {
       "employeeId": "E-267", 
       "companyId": "D-432"
  },
  "name": "Spider Man", 
  "email": "spman@somedomain.com", 
  "phoneNumber": "+91-476253455"
}

However, the id field will be exposed in all of the responses. 但是,id字段将在所有响应中公开。 But maybe it's not a real problem, because when you use a composite id it usually means that the id is not only an abstract identifier, but its parts have meaningful content which should appear in the entity body. 但也许这不是一个真正的问题,因为当你使用复合id时,它通常意味着id不仅是一个抽象的标识符,而且它的部分具有应该出现在实体主体中的有意义的内容。

Actually, I'm thinking of adding these lines to my own code too .... :) 实际上,我正在考虑将这些行添加到我自己的代码中.... :)

I had a similar problem and I couldn't find a solution for creating new entities via the POST /entities endpoint. 我有类似的问题,我找不到通过POST /entities端点创建新实体的解决方案。 However, you can also create a new entity via PUT /entities/{newId} endpoint. 但是,您也可以通过PUT /entities/{newId}端点创建新实体。 And the converter works fine for these endpoints. 转换器适用于这些端点。 I also completely denied the POST endpoint avoiding the 500 responses: 我还完全否定了POST端点,避免了500个响应:

  @PostMapping(value = "/themeMessages")
  public ResponseEntity<Void> postThemeMessage() {

    return new ResponseEntity<>(HttpStatus.METHOD_NOT_ALLOWED);
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM