Java 使用 Spring Data Rest 时暴露所有 ID

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30912826/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 10:22:00  来源:igfitidea点击:

Expose all IDs when using Spring Data Rest

javaspringrestspring-mvcspring-data-rest

提问by Baiteman

I'd like to expose all IDs using a Spring Rest interface.

我想使用 Spring Rest 接口公开所有 ID。

I know that per default an ID like this will not be exposed via the rest interface:

我知道默认情况下,这样的 ID 不会通过其余接口公开:

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(unique=true, nullable=false)
    private Long id;

I'm aware that I can use this to expose the ID for User:

我知道我可以使用它来公开以下 ID User

@Configuration
public class RepositoryConfig extends RepositoryRestMvcConfiguration {
    @Override
    protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(User.class);
    }
}

But is there an easy way to expose all IDs without manually maintaining a list in this configureRepositoryRestConfigurationmethod?

但是有没有一种简单的方法来公开所有 ID,而无需在此configureRepositoryRestConfiguration方法中手动维护列表?

采纳答案by Justin Lewis

Currently, there is no way to do this provided by SDR. This issueon the SDR Jira tracker gives some explanation as to why this isn't (and perhaps shouldn't) be possible.

目前,SDR 没有提供这种方法。SDR Jira 跟踪器上的这个问题解释了为什么这不可能(也许不应该)。

The argument is basically that since the IDs are already contained within the selflinks in the response, you don't need to expose them as properties of the object itself.

论点基本上是因为 ID 已经包含在self响应中的链接中,所以您不需要将它们作为对象本身的属性公开。

That said, you may be able to use reflection to retrieve all classes that have a javax.persistence.Idannotation and then call RepositoryRestConfiguration#exposeIdsFor(Class<?>... domainTypes).

也就是说,您可以使用反射来检索所有具有javax.persistence.Id注释的类,然后调用RepositoryRestConfiguration#exposeIdsFor(Class<?>... domainTypes).

回答by Mark

I discovered that if you name the @Idfield 'Id' it will display in the JSON if you have a public getter for the Id. The Id will show up as a JSON key called 'id'

我发现,如果您将@Id字段命名为' Id',如果您有一个公共的 .getter,它将显示在 JSON 中Id。Id 将显示为名为 ' id'的 JSON 密钥

For example: @Id @Column(name="PERSON_ROLE_ID") private Long Id;

例如: @Id @Column(name="PERSON_ROLE_ID") private Long Id;

This also works for @EmbeddedIdfields called 'Id' as well as long as it has a public getter. In this case the fields of the Id will show up as a JSON object.

这也适用于@EmbeddedId名为“ Id”的字段,只要它具有公共 getter。在这种情况下,Id 的字段将显示为 JSON 对象。

For example: @EmbeddedId private PrimaryKey Id;

例如: @EmbeddedId private PrimaryKey Id;

Surprisingly this is case sensitive, calling id 'id' doesn't work even though it would be a more conventional name for a Java field.

令人惊讶的是,这是区分大小写的,调用 id ' id' 不起作用,即使它是 Java 字段的更传统的名称。

I should say that I discovered this completely by accident so I don't know if this is an accepted convention or will work with previous or future versions of Spring Data and REST. Therefore I have included the relevant parts of my maven pom just incase it's sensittive to versions...

我应该说我完全是偶然发现的,所以我不知道这是否是公认的约定,或者是否适用于 Spring Data 和 REST 的先前或未来版本。因此,我已经包含了我的 maven pom 的相关部分,以防它对版本敏感......

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.0.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-rest</artifactId>
    </dependency>
    <dependency>
        <groupId>com.oracle</groupId>
        <artifactId>ojdbc7</artifactId>
        <version>12.1.0.2</version>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>
</dependencies>

回答by raksja

Proabably you can try this to include all id fields. I havent tried it yet, but will keep posted.

很可能你可以试试这个来包含所有的 id 字段。我还没有尝试过,但会继续发布。

 public class ExposeAllRepositoryRestConfiguration extends RepositoryRestConfiguration {
    @Override
    public boolean isIdExposedFor(Class<?> domainType) {
        return true;
        }
    }

Excerpt from this link

摘自此链接

回答by Dario Seidl

You can use this method to find all @Entityclasses of the EntityManagerFactory:

您可以使用此方法查找@EntityEntityManagerFactory 的所有类:

private List<Class<?>> getAllManagedEntityTypes(EntityManagerFactory entityManagerFactory) {
    List<Class<?>> entityClasses = new ArrayList<>();
    Metamodel metamodel = entityManagerFactory.getMetamodel();
    for (ManagedType<?> managedType : metamodel.getManagedTypes()) {
        Class<?> javaType = managedType.getJavaType();
        if (javaType.isAnnotationPresent(Entity.class)) {
            entityClasses.add(managedType.getJavaType());
        }
    }
    return entityClasses;
}

then, to expose the IDs for all your entity classes:

然后,公开所有实体类的 ID:

@Configuration
public class RestConfig extends RepositoryRestMvcConfiguration {

    @Bean
    public RepositoryRestConfigurer repositoryRestConfigurer(EntityManagerFactory entityManagerFactory) {
        List<Class<?>> entityClasses = getAllManagedEntityTypes(entityManagerFactory);

        return new RepositoryRestConfigurerAdapter() {

            @Override
            public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
                for (Class<?> entityClass : entityClasses) {
                    config.exposeIdsFor(entityClass);
                }
            }
    }
}

回答by kidfruit

You can add all your entity classes by exposeIdsFor. Replace "db.entity" to whick package you put your entities.

您可以通过ExposureIdsFor添加所有实体类。将“db.entity”替换为放置实体的包。

@Configuration
public class CustomRepositoryRestConfigurer extends RepositoryRestConfigurerAdapter {
    Logger logger = Logger.getLogger(this.getClass());

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        Set<String> classNameSet = ClassTool.getClassName("db.entity", false);
        for (String className : classNameSet) {
            try {
                config.exposeIdsFor(Class.forName(className));
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        logger.info("exposeIdsFor : " + classNameSet);
    }
}

The ClassTool is my custom function to get class from given package, you can write by yourself.

ClassTool 是我的自定义函数,用于从给定的包中获取类,您可以自己编写。

回答by Stephan

Here is what worked perfectly for me (source here):

这是对我来说完美的方法(来源在这里):

@Configuration
public class RepositoryRestConfig extends RepositoryRestConfigurerAdapter {

  @Override
  public void configureRepositoryRestConfiguration(final RepositoryRestConfiguration config) {

    final ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(
        false);
    provider.addIncludeFilter(new AnnotationTypeFilter(Entity.class));

    final Set<BeanDefinition> beans = provider.findCandidateComponents("com.your.domain");

    for (final BeanDefinition bean : beans) {
      try {
        config.exposeIdsFor(Class.forName(bean.getBeanClassName()));
      } catch (final ClassNotFoundException e) {
        // Can't throw ClassNotFoundException due to the method signature. Need to cast it
        throw new IllegalStateException("Failed to expose `id` field due to", e);
      }
    }
  }
}

It finds all beans with the @Entity annotation and exposes them.

它找到所有带有 @Entity 注释的 bean 并公开它们。

回答by mekazu

If you want to expose the id field for all your entity classes:

如果要公开所有实体类的 id 字段:

import java.util.stream.Collectors;

import javax.persistence.EntityManager;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;

@Configuration
public class MyRepositoryRestConfigurerAdapter extends RepositoryRestConfigurerAdapter {

    @Autowired
    private EntityManager entityManager;

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(entityManager.getMetamodel().getEntities().stream().map(e -> e.getJavaType()).collect(Collectors.toList()).toArray(new Class[0]));
    }

}

回答by Phearun Rath

Try this configuration. It works perfectly fine for me.

试试这个配置。它对我来说非常好。

@Configuration
public class RestConfiguration extends RepositoryRestConfigurerAdapter{

      @PersistenceContext
      private EntityManager entityManager;

      @Override
      public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
           //TODO: Expose for specific entity!
           //config.exposeIdsFor(Officer.class);
           //config.exposeIdsFor(Position.class);

           //TODO: Expose id for all entities!
           entityManager.getMetamodel().getEntities().forEach(entity->{
                try {
                     System.out.println("Model: " + entity.getName());
                     Class<? extends Object> clazz = Class.forName(String.format("yourpackage.%s", entity.getName()));
                     config.exposeIdsFor(clazz);
                } catch (Exception e) {
                     System.out.println(e.getMessage());
                }
            });
    }
}

回答by David B.

Please find a simple solution for this, avoiding to find entities related.

请为此找到一个简单的解决方案,避免查找相关实体。

@Component
public class EntityExposingIdConfiguration extends RepositoryRestConfigurerAdapter {

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        try {
            Field exposeIdsFor = RepositoryRestConfiguration.class.getDeclaredField("exposeIdsFor");
            exposeIdsFor.setAccessible(true);
            ReflectionUtils.setField(exposeIdsFor, config, new ListAlwaysContains());
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

    class ListAlwaysContains extends ArrayList {

        @Override
        public boolean contains(Object o) {
            return true;
        }
    }
}

回答by Francois Gengler

Following piece of code looks prettier:

以下代码看起来更漂亮:

.exposeIdsFor(entityManager.getMetamodel().getEntities().stream().map(entityType -> entityType.getJavaType()).toArray(Class[]::new))