Spring Data Rest遇到复合主键

如果项目持久层使用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 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.printf("toRequestId(%s,%s)\n", serializable, clazz);
        System.out.println(serializable.getClass());
        return threadLocal.get();
    }

    @Override
    public boolean supports(Class clazz) {
        System.out.printf("supports(%s)\n", clazz);
        return Arrays.asList(FilmActor.class, FilmCategory.class).contains(clazz);
    }
}

现在访问 http://localhost:8080/FilmActor/1,1 就能获取film_actor表
中actor_id和film_id都是1的记录了。


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、性能问题和安全问题
……

你可能感兴趣的:(玩玩)