spring 数据以复合主键休息
spring data rest with composite primary key
我使用 spring 数据剩余作为 crud。但是当实体有复合主键时,我不知道如何通过给主键来获取实体。
河流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;
}
}
RiverPKclass:
@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 class:
@RepositoryRestResource(path = "river")
public interface RiverDAO extends JpaRepository<River, RiverPK> {
}
然后我可以调用 get http://localhost:8080/river/, and also create new entity to db by call post http://localhost:8080/river/ {river json}
获取河流数据
河流json是:
id": {
"name": "1",
"upcode": 2,
"downcode": 3
},
"length": 4.4,
"date": 1493740800000,
"comment": "6"
}
在spring data rest doc中,应该可以调用get localhost:8080/river/1(主键)获取主键为1的实体。这个可以当实体只有一个主键时工作。但是我的实体河流有复合主键作为 RiverPK。如果我调用 get localhost:8080/river/{name='1',upcode=2,downcode=3},它 returns 一个错误 "No converter found capable of converting from type [java.lang.String] to type [com.example.db.entity.RiverPK]",我的意思是 spring 使用{name='1',upcode=2,downcode=3} 作为字符串,但不是 RiverPK 类型。
问题是如何调用 get\put\delete 与其他普通实体一样使用复合主键?
有一个jira问题你可以看看:
https://jira.spring.io/browse/DATAREST-598
您可能对这条评论特别感兴趣
您还可以找到 github link to a sample project. It uses a BackendIdConverter 将复合键转换为字符串并返回。所以诀窍是将您的复合id转换为可用作路径段的字符串。
您可能也对这个答案感兴趣
在学习 Customizing HATEOAS link generation for entities with composite ids 之后,我找到了一个更通用的解决方案。
首先,创建一个 SpringUtil 以从 spring.
获取 bean
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。
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;
}
}
之后。你可以做你想做的事。
下面有一个示例。
- 如果实体只有一个 属性 pk,你可以使用
localhost:8080/demo/1 正常。根据我的代码,假设 pk
有注解“@Id”。
- 如果实体有组成pk,假设pk是demoId类型,并且有
注解“@EmbeddedId”,可以使用localhost:8080/demo/{demoId
json} 到 get/put/delete。而你自己link也会一样。
我使用 spring 数据剩余作为 crud。但是当实体有复合主键时,我不知道如何通过给主键来获取实体。
河流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;
}
}
RiverPKclass:
@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 class:
@RepositoryRestResource(path = "river")
public interface RiverDAO extends JpaRepository<River, RiverPK> {
}
然后我可以调用 get http://localhost:8080/river/, and also create new entity to db by call post http://localhost:8080/river/ {river json}
获取河流数据河流json是:
id": {
"name": "1",
"upcode": 2,
"downcode": 3
},
"length": 4.4,
"date": 1493740800000,
"comment": "6"
}
在spring data rest doc中,应该可以调用get localhost:8080/river/1(主键)获取主键为1的实体。这个可以当实体只有一个主键时工作。但是我的实体河流有复合主键作为 RiverPK。如果我调用 get localhost:8080/river/{name='1',upcode=2,downcode=3},它 returns 一个错误 "No converter found capable of converting from type [java.lang.String] to type [com.example.db.entity.RiverPK]",我的意思是 spring 使用{name='1',upcode=2,downcode=3} 作为字符串,但不是 RiverPK 类型。
问题是如何调用 get\put\delete 与其他普通实体一样使用复合主键?
有一个jira问题你可以看看: https://jira.spring.io/browse/DATAREST-598
您可能对这条评论特别感兴趣
您还可以找到 github link to a sample project. It uses a BackendIdConverter 将复合键转换为字符串并返回。所以诀窍是将您的复合id转换为可用作路径段的字符串。
您可能也对这个答案感兴趣
在学习 Customizing HATEOAS link generation for entities with composite ids 之后,我找到了一个更通用的解决方案。
首先,创建一个 SpringUtil 以从 spring.
获取 beanimport 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。
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;
}
}
之后。你可以做你想做的事。
下面有一个示例。
- 如果实体只有一个 属性 pk,你可以使用 localhost:8080/demo/1 正常。根据我的代码,假设 pk 有注解“@Id”。
- 如果实体有组成pk,假设pk是demoId类型,并且有 注解“@EmbeddedId”,可以使用localhost:8080/demo/{demoId json} 到 get/put/delete。而你自己link也会一样。