Spring Data Rest遇到複合主鍵
阿新 • • 發佈:2019-01-31
如果專案持久層使用Spring Data JPA且某些資料表中含有複合主鍵(聯合主鍵),使用Spring Data Rest生成的介面如何訪問這些資料表中的某個主鍵對應的資料呢?
假設資料庫有2個有複合主鍵的資料表film_actor和film_category,對應以下4個類。
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
import java.sql.Timestamp;
@Entity
@Table(name = "film_actor")
public class FilmActor implements Serializable {
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "actorId", column = @Column(name = "actor_id", nullable = false)),
@AttributeOverride(name = "filmId", column = @Column(name = "film_id", nullable = false))})
private FilmActorId id;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "last_update", nullable = false, length = 19)
private Date lastUpdate;
//constructor、getter/setter
}
@Embeddable
public class FilmActorId implements java.io.Serializable {
@Column(name = "actor_id", nullable = false )
private short actorId;
@Column(name = "film_id", nullable = false)
private short filmId;
//constructor、getter/setter、equals、hashCode
}
@Entity
@Table(name = "film_category")
@IdClass(FilmCategoryPK.class)
public class FilmCategory {
@Id
@Column(name = "film_id", nullable = false)
private short filmId;
@Id
@Column(name = "category_id", nullable = false)
private byte categoryId;
@Basic
@Column(name = "last_update", nullable = false)
private Timestamp lastUpdate;
//constructor、getter/setter、equals、hashCode
}
public class FilmCategoryPK implements Serializable {
@Column(name = "film_id", nullable = false)
@Id
private short filmId;
@Column(name = "category_id", nullable = false)
@Id
private byte categoryId;
//constructor、getter/setter、equals、hashCode
}
以上程式碼代表了ORM的兩種方式。
那如何通過Spring Data Rest生成的介面獲取film_actor表中ID都是1的記錄呢?
那就涉及如何將請求URL轉化為實體類ID了。需要新增如下配置
import org.springframework.data.rest.webmvc.spi.BackendIdConverter;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.util.Arrays;
@Component
public class IdConverter implements BackendIdConverter {
private ThreadLocal<String> threadLocal = new ThreadLocal<>();
@Override
public Serializable fromRequestId(String s, Class<?> clazz) {
System.out.println(String.format("fromRequestId(%s,%s)", s, clazz));
threadLocal.set(s);
String[] ss = s.split(",");
long p1 = Long.parseLong(ss[0]);
long p2 = Long.parseLong(ss[1]);
if (clazz == FilmActor.class)
return new FilmActorId(((short) p1), ((short) p2));
if (clazz == FilmCategory.class)
return new FilmCategoryPK(((short) p1), ((byte) p2));
return null;
}
@Override
public String toRequestId(Serializable serializable, Class<?> clazz) {
System.out.println(String.format("toRequestId(%s,%s)", serializable, clazz));
System.out.println(serializable.getClass());
return threadLocal.get();
}
@Override
public boolean supports(Class<?> clazz) {
System.out.println(String.format("supports(%s)", clazz));
return Arrays.asList(FilmActor.class, FilmCategory.class).contains(clazz);
}
}
Spring data Rest生成的介面預設不輸出ID,如果需要輸出ID,可以配置一個Bean。如下是FilmActor、 FilmCategory都暴露ID的配置。
import org.springframework.context.annotation.Bean;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;
@Bean
public RepositoryRestConfigurer repositoryRestConfigurer() {
return new RepositoryRestConfigurerAdapter() {
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(FilmActor.class, FilmCategory.class);
}
};
}
附:
對Spring Data Rest的評價:
優點:用極少的程式碼就能實現資料庫常用CRUD操作向RESTful API的轉化
缺點:
1、springfox swagger還不能探測到生成的介面
2、與Spring Data JPA的結合還有很多問題
3、生成的介面難以應對複雜的業務場景
4、效能問題和安全問題
……