【问题标题】:Creating Resource with references using spring data rest使用弹簧数据休息创建具有引用的资源
【发布时间】:2017-09-18 07:53:30
【问题描述】:

我正在使用 spring data rest,我通过 spring data rest 公开了以下实体

捐赠请求

@Data
@Entity
@Table(name="donation_request",schema="public")
public class DonationRequest {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="donation_request_id")
    Integer donationRequestId;

    @Column(name="expiry_datetime")
    Date expiryDatetime;

    @Column(name="blood_group")
    String bloodGroup;

    @Column(name="no_of_bottles")
    String noOfBottles;

    @OneToOne
    @JoinColumn(name="hospital_id")
    Hospital hospital;

    @OneToOne
    @JoinColumn(name="user_data_id")
    UserData requester;

    @Column(name="active")
    Boolean active;

}

医院

@Data
@Entity
@Table(name="hospital",schema="public")
public class Hospital {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="hospital_id")
    Integer hospitalId;

    @Column(name="name")
    String name;

    @Column(name="address")
    String address;

    @Column(name="loc",columnDefinition = "geometry")
    Point loc;

}

现在我有一个 android 客户端,它具有与上述相同的类定义。医院在安卓客户端启动时被缓存。现在我想在服务器上创建一个donationRequest 实体。我可以通过将donationRequest 对象的json 发布到/api/donationRequests 来轻松做到这一点。这个 json 也包含医院对象。但是新创建的donationRequest 和hospital 并没有链接在一起。

postman 中以下类型的 json 不会创建链接:

{
    "bloodGroup":"AB+",
    "hospital":{
        "hospitalId":1
    }
}

我知道以下 json 确实会创建链接:

{
    "bloodGroup":"AB+",
    "hospital":"/api/hospitals/1"
}

我的问题是如何使用第一种类型的 json 创建链接,因为这是从 android 客户端序列化 dontaionRequest 对象的自然方式?此外,我希望通过 /api/hospitals 暴露医院,因此 删除该休息资源不是一种选择

【问题讨论】:

    标签: android spring-boot spring-data-rest


    【解决方案1】:

    这可以通过使用自定义 HttpMessageConverter 并定义自定义内容类型来实现,该类型可以是标准以外的任何内容(我使用了 application/mjson):

    MHttpMessageConverter.java

    public class MHttpMessageConverter implements HttpMessageConverter<Object>{
        @Override
        public boolean canRead(Class<?> aClass, MediaType mediaType) {
            if (mediaType.getType().equalsIgnoreCase("application")
                    && mediaType.getSubtype().equalsIgnoreCase("mjson"))
                return true;
            else
                return false;
        }
    
        @Override
        public boolean canWrite(Class<?> aClass, MediaType mediaType) {
            return false;
        }
    
        @Override
        public List<MediaType> getSupportedMediaTypes() {
            return new ArrayList<>(Arrays.asList(MediaType.APPLICATION_JSON));
        }
    
        @Override
        public Object read(Class<?> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
            ObjectMapper mapper = new ObjectMapper();
            Object obj = mapper.readValue(httpInputMessage.getBody(),aClass);
            return obj;
        }
    
        @Override
        public void write(Object o, MediaType mediaType, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {
    
        }
    }
    

    CustomRestConfiguration.java

    @Configuration
    public class CustomRestConfiguration extends RepositoryRestConfigurerAdapter {
    
        @Override
        public void configureHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
            messageConverters.add(new MHttpMessageConverter());
        }
    }
    

    【讨论】:

    • 非常有趣的解决方案。自定义控制器不会更容易吗?
    • 使用自定义控制器,我必须分别处理所有实体。
    【解决方案2】:

    Spring Data REST 正在使用HATEOAS。要引用相关资源,我们必须使用它们的链接:

    先创建医院

    POST /api/hospitals
    {
        //...
    }
    

    回复

    {
        //...
        "_links": [
            "hostpital": "http://localhost/api/hospitals/1",
            //...
        ]
    }
    

    然后获取“hospital”(或“self”)链接并将其添加到“donationRequests”有效负载中

    POST /api/donationRequests
    {
        "bloodGroup":"AB+",
        "hospital": "http://localhost/api/hospitals/1"
    }
    

    另一种方法 - 在没有医院的情况下创建第一个“捐赠请求”

    POST /api/donationRequests
    {
        //...
    }
    

    回复

    {
        //...
        "_links": [
            "hostpital": "http://localhost/api/donationRequests/1/hospital"
            //...
        ]
    }
    

    然后将医院放到donationRequests/1/hospital,在你的payload中使用文本链接到医院(注意Content-Type:text/uri-list)

    PUT http://localhost/api/donationRequests/1/hospital (Content-Type: text/uri-list)
    http://localhost/api/hospitals/1
    

    信息:Repository resources - The association resource

    更新

    如果需要处理没有资源链接的问题,我们必须发送custom rest controller

    【讨论】:

    • 两件事:- 1- 医院已经创建。我只是想参考一下。 2-我已经告诉过我知道可以使用其余资源链接来创建关联链接。我想知道是否有其他解决方案?
    • 检查我的答案。
    猜你喜欢
    • 2018-12-16
    • 2015-04-22
    • 2018-07-13
    • 2017-11-01
    • 2018-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多