重新启动后不一致地“发现”Spring数据休息资源

我正在使用 Spring Data Rest 来公开我可以在我的用户界面中使用的其余端点。但是,在测试过程中,我注意到当点击 base rest url (http://localhost:8080/rest) 时,端点的暴露不一致。我正在使用基于注释的 RepositoryDe​​tectionStrategies。

如果您能帮助我理解和解决问题,我将不胜感激。

示例:

首次启动:所有端点都正确暴露:

{
  "_links" : {
    "orders" : {
      "href" : "http://localhost:8080/rest/orders{?page,size,sort}","templated" : true
    },"reports" : {
      "href" : "http://localhost:8080/rest/reports{?page,"buySells" : {
      "href" : "http://localhost:8080/rest/positions{?page,"profile" : {
      "href" : "http://localhost:8080/rest/profile"
    }
  }
}

在没有任何代码或配置更改的情况下重新启动后:

{
  "_links" : {
    "orders" : {
      "href" : "http://localhost:8080/rest/orders{?page,"profile" : {
      "href" : "http://localhost:8080/rest/profile"
    }
  }
}

如您所见,在应用程序重新启动后,报告端点未公开。 曝光失败非常不一致;有时所有 3 个端点都未公开,有时缺少 1 或 2 个(不一致),有时一切正常。

我无法在日志中找到任何故障,即使将其放入 TRACE 也是如此。

配置

这里是主要的pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.rvh</groupId>
    <artifactId>project-parent</artifactId>
    <version>0.0.1-snAPSHOT</version>
    <name>project-parent</name>
    <packaging>pom</packaging>

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

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <slf4j.version>1.7.30</slf4j.version>
    </properties>


    <modules>
        <!-- <module>compiler-plugin-java-9</module> --> <!-- We haven't upgraded to java 9. -->
        <module>web</module>
        <module>api-engine</module>
    </modules>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
                <version>1.2.3</version>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>1.2.3</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>1.7.30</version>
            </dependency>
            <dependency>
                <groupId>nl.rvh</groupId>
                <artifactId>business-rule-validator</artifactId>
                <version>1.0</version>
            </dependency>
<!--            <dependency>-->
<!--                <groupId>org.springframework.boot</groupId>-->
<!--                <artifactId>spring-boot-maven-plugin</artifactId>-->
<!--                <version>2.5.3</version>-->
<!--            </dependency>-->
        </dependencies>
    </dependencyManagement>

    <dependencies>
<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-devtools</artifactId>-->
<!--            <optional>true</optional>-->
<!--        </dependency>-->
    </dependencies>

    <build>
        <finalName>collector</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <configuration>
                            <mainClass>com.rvh.collector.CollectorApplication</mainClass>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!--            mvn sonar:sonar \-->
            <!--            -Dsonar.projectKey=baralga \-->
            <!--            -Dsonar.organization=baralga \-->
            <!--            -Dsonar.host.url=https://sonarcloud.io \-->
            <!--            -Dsonar.login=<GENERATED_TOKEN>-->
            <plugin>
                <groupId>org.sonarsource.scanner.maven</groupId>
                <artifactId>sonar-maven-plugin</artifactId>
                <version>3.7.0.1746</version>
            </plugin>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.8.6</version>
                <executions>
                    <execution>
                        <id>prepare-agent</id>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>report</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <useSystemClassLoader>false</useSystemClassLoader>
                    <argLine>-Dfile.encoding=UTF8</argLine>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

这里是 web 模块 pom

    <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>com.rvh</groupId>
    <artifactId>project-parent</artifactId>
    <version>0.0.1-snAPSHOT</version>
  </parent>

  <artifactId>collector</artifactId>
  <version>0.0.1-snAPSHOT</version>
  <name>collector</name>
  <description>collector application</description>
  <packaging>war</packaging>
  <properties>
    <main.basedir>${basedir}/../..</main.basedir>
    <m2eclipse.wtp.contextRoot>/</m2eclipse.wtp.contextRoot>
    <java.version>11</java.version>
    <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco/jacoco.xml
    </sonar.coverage.jacoco.xmlReportPaths>

  </properties>

  <dependencies>
    <!-- Compile -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-taglibs</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-rest</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-data</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    <!--        <dependency>-->
    <!--            <groupId>org.springframework.boot</groupId>-->
    <!--            <artifactId>spring-boot-devtools</artifactId>-->
    <!--            <optional>true</optional>-->
    <!--        </dependency>-->

    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-core</artifactId>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
    </dependency>

    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
    </dependency>
    <dependency>
      <groupId>org.openjfx</groupId>
      <artifactId>javafx-media</artifactId>
      <version>17-ea+14</version>
    </dependency>

    <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient</artifactId>
      <version>4.5.13</version>
    </dependency>

    <dependency>
      <groupId>com.rvh.api.engine</groupId>
      <artifactId>apiEngine</artifactId>
      <version>1.0-snAPSHOT</version>
    </dependency>

    <!-- Provided -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.tomcat.embed</groupId>
      <artifactId>tomcat-embed-jasper</artifactId>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>nl.rvh.trade</groupId>
      <artifactId>kraken-api</artifactId>
      <version>1.0-snAPSHOT</version>
    </dependency>
    <dependency>
      <groupId>nl.rvh</groupId>
      <artifactId>business-rule-validator</artifactId>
    </dependency>

    <!-- Test -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>


</project>

这是主类的注释方式:

@Configuration
@ComponentScan("com.rvh.**")
@EnableAutoConfiguration
@EnableJpaRepositories("com.rvh.collector")
@EnableScheduling
public class CollectorApplication {

这是其余的配置类:

@Configuration
public class RestRepositoryConfig implements RepositoryRestConfigurer {

  @Override
  public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config,CorsRegistry cors) {
    //Only expose annotated repositories
    config.setRepositoryDetectionStrategy(RepositoryDetectionStrategy.RepositoryDetectionStrategies.ANNOTATED);
    config.setBasePath("/rest");

    ExposureConfiguration exposureConfiguration = config.getExposureConfiguration();
    exposureConfiguration.withItemExposure((metadata,httpMethods) -> httpMethods
        .disable(HttpMethod.PATCH,HttpMethod.DELETE,HttpMethod.TRACE,HttpMethod.HEAD,HttpMethod.PUT,HttpMethod.POST));

  }
}

和我的 rest 存储库,它们都是 com.rvh.collector.rest 包的一部分。

@RepositoryRestResource
@PreAuthorize("hasRole('ROLE_ADMIN')")
public interface OrdersRest extends PagingAndSortingRepository<Order,Integer> {

}

@RepositoryRestResource(path = "positions")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public interface PositionRestRepo extends PagingAndSortingRepository<BuySell,Integer> {


}

@RepositoryRestResource
@PreAuthorize("hasRole('ROLE_ADMIN')")
public interface ReportsDao extends PagingAndSortingRepository<Report,Long> {

  @Query("select report from Report report where report.accountId in "
      + "(select acc.id from User user join user.accounts acc where user.username = ?#{ principal?.username }) ")
  Iterable<Report> findAll();

  @Query("select report from Report report where report.accountId in "
      + "(select acc.id from User user join user.accounts acc where user.username = ?#{ principal?.username })"
      + "and report.id = :aLong ")
  Optional<Report> findById(Long aLong);


}
huangyu0047 回答:重新启动后不一致地“发现”Spring数据休息资源

我相信我发现了问题;

我有同一个实体的多个存储库。例如:我有一个 OrdersDao 和一个 OrderRestRepo 用于 Order 实体,它们都是一个存储库接口。为同一实体创建 2 个 repo 的原因是因为我希望 OrderRestRepo 使用 @preauthorize 功能,我不想将其应用于 OrdersDao,因为它也被我的一个调度程序使用。

当转移到单个存储库、单个实体时,我没有看到端点的不一致暴露(持续重启大约 6 / 7 次)。

对于调度程序问题,我可能会使用以下描述的解决方案 #2:SecurityContext with default System authentication/user

更新: 我在 Spring Github 上发现了一些缺陷,这解释了我注意到的确切行为: https://github.com/spring-projects/spring-data-rest/issues/1286

这似乎是一个已知问题。建议的解决方案是在公开的存储库上使用 @Primary 注释,并将未公开的存储库设置为 Exported = False。从列出的缺陷来看,@Primary 最初似乎没有按预期工作,但随着时间的推移,这可能已得到修复。缺陷仍被标记为开放,所以我只是要尝试建议的,否则驻留在初始解决方案。

更新 2

到目前为止,使用 @Primary 到应该作为 Rest 公开的存储库,按预期工作。所以我现在有 2 个同一个实体的 repo。

@Repository
@Qualifier(value = "ordersDao")
public interface OrdersDao extends JpaRepository<Order,Integer>,JpaSpecificationExecutor<Order> {

@RepositoryRestResource
@PreAuthorize("hasRole('ROLE_ADMIN')")
@Primary 
public interface OrdersRest extends PagingAndSortingRepository<Order,Integer> {

当我使用基于注释的策略时,我不必将 Exporter=false 属性设置为 OrdersDao。 (那个 Dao 也没有使用 @(Repository)RestResource 注释,否则它是必需的)。

一旦我能够接受这个答案,我就会接受

本文链接:https://www.f2er.com/8061.html

大家都在问