弹簧数据休息与复合主键 [英] spring data rest with composite primary key

查看:95
本文介绍了弹簧数据休息与复合主键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用spring data rest for crud。但是当实体具有复合主键时,我不知道如何通过给出主键来获得实体。

I use spring data rest for crud. But when the entity has composite primary keys, I dont know how to to get an entity by giving the primary key.

River class:

River class:

@Entity
public class River {
    private RiverPK id;
    private Double length;
    private Timestamp date;
    private String comment;


    @Basic
    @Column(name = "length")
    public Double getLength() {
        return length;
    }

    public void setLength(Double length) {
        this.length = length;
    }

    @Basic
    @Column(name = "date")
    public Timestamp getDate() {
        return date;
    }

    public void setDate(Timestamp date) {
        this.date = date;
    }

    @Basic
    @Column(name = "comment")
    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    @Id
    public RiverPK getId() {
        return id;
    }

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

RiverPK类:

@Embeddable
public class RiverPK implements Serializable {
    private String name;
    private int upcode;
    private int downcode;

    @Column(name = "name")
    public String getName() {
        return name;
    }

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

    @Column(name = "upcode")
    public int getUpcode() {
        return upcode;
    }

    public void setUpcode(int upcode) {
        this.upcode = upcode;
    }

    @Column(name = "downcode")
    public int getDowncode() {
        return downcode;
    }

    public void setDowncode(int downcode) {
        this.downcode = downcode;
    } 

}

RiverDAO类:

RiverDAO class:

@RepositoryRestResource(path = "river")
public interface RiverDAO extends JpaRepository<River, RiverPK> {
}

然后我可以通过调用get http:// localhost:8080 / river / ,还可以通过调用post http:// localhost:8080 / river / {river json}

Then I can get river data by call get http://localhost:8080/river/, and also create new entity to db by call post http://localhost:8080/river/ {river json}

river json是:

river json is:

id": {

    "name": "1",
    "upcode": 2,
    "downcode": 3

},
"length": 4.4,
"date": 1493740800000,
"comment": "6"
}

在Spring数据休息文档中,它应该能够调用get localhost:8080 / river / 1(主键)来获取主键为1的实体。当实体只有一个主键时,这可以工作。但我的实体河有复合主键作为RiverPK。如果我调用get localhost:8080 / river / {name ='1',upcode = 2,downcode = 3},它返回错误无转换器发现能够从类型转换[java .lang.String]输入[com.example.db.entity.RiverPK],我的意思是使用{name ='1',upcode = 2,downcode = 3}作为String,但不是RiverPK类型。

In spring data rest doc, it should be able to call get localhost:8080/river/1 (the primary key) to get the entity which primary key is 1. This can work when the entity has only one primary key. But my entity river has composite primary keys as RiverPK. If I call get localhost:8080/river/{name='1',upcode=2,downcode=3}, it returns a error "No converter found capable of converting from type [java.lang.String] to type [com.example.db.entity.RiverPK]", I means spring use {name='1',upcode=2,downcode=3} as a String, but not RiverPK type.

问题是如何使用复合主键作为其他正常实体调用get\put \ delete?

The question is how to call get\put\delete with composite primary keys as other normal entity?

推荐答案

学习为具有复合ID的实体自定义HATEOAS链接生成,我发现了一个更通用的解决方案。

After learn from Customizing HATEOAS link generation for entities with composite ids, I found a much more generic solution.

首先,创建一个SpringUtil来从spring获取bean 。

First, create a SpringUtil to get bean from spring.

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if(SpringUtil.applicationContext == null) {
            SpringUtil.applicationContext = applicationContext;
        }
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public static Object getBean(String name){
        return getApplicationContext().getBean(name);
    }

    public static <T> T getBean(Class<T> clazz){
        return getApplicationContext().getBean(clazz);
    }

    public static <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }
}

然后,实施BackendIdConverter。

Then, implement BackendIdConverter.

import com.alibaba.fastjson.JSON;
import com.example.SpringUtil;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.webmvc.spi.BackendIdConverter;
import org.springframework.stereotype.Component;

import javax.persistence.EmbeddedId;
import javax.persistence.Id;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.net.URLEncoder;

@Component
public class CustomBackendIdConverter implements BackendIdConverter {

    @Override
    public boolean supports(Class<?> delimiter) {
        return true;
    }

    @Override
    public Serializable fromRequestId(String id, Class<?> entityType) {
        if (id == null) {
            return null;
        }

        //first decode url string
        if (!id.contains(" ") && id.toUpperCase().contains("%7B")) {
            try {
                id = URLDecoder.decode(id, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }

        //deserialize json string to ID object
        Object idObject = null;
        for (Method method : entityType.getDeclaredMethods()) {
            if (method.isAnnotationPresent(Id.class) || method.isAnnotationPresent(EmbeddedId.class)) {
                idObject = JSON.parseObject(id, method.getGenericReturnType());
                break;
            }
        }

        //get dao class from spring
        Object daoClass = null;
        try {
            daoClass = SpringUtil.getBean(Class.forName("com.example.db.dao." + entityType.getSimpleName() + "DAO"));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //get the entity with given primary key
        JpaRepository simpleJpaRepository = (JpaRepository) daoClass;
        Object entity = simpleJpaRepository.findOne((Serializable) idObject);
        return (Serializable) entity;

    }

    @Override
    public String toRequestId(Serializable id, Class<?> entityType) {
        if (id == null) {
            return null;
        }

        String jsonString = JSON.toJSONString(id);

        String encodedString = "";
        try {
            encodedString = URLEncoder.encode(jsonString, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return encodedString;
    }
}

之后。你可以做你想做的事。

After that. you can do what you want.

下面有一个样本。


  • 如果实体具有单个属性pk,则可以正常使用
    localhost:8080 / demo / 1。根据我的代码,假设pk
    有注释@Id。

  • 如果实体已经编写了pk,假设pk是demoId类型,并且有
    注释@EmbeddedId,您可以使用localhost:8080 / demo / {demoId
    json}来获取/放置/删除。你的自我链接也一样。

这篇关于弹簧数据休息与复合主键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆