使用spring-boot-2.2.1删除hateoas链接中的\u

cyej8jka  于 2021-06-30  发布在  Java
关注(0)|答案(2)|浏览(428)

我正在使用spring-boot-2.2.1和spring-hateoas。超媒体链接工作正常,但我明白了 _embedded 属性返回链接时,请在此处查找以下代码供参考和github中的项目,
终结点:
a) 会回来的 CollectionModel => localhost:8099/api/v1/capability/list/noembedded
以及
b) 将返回list<entitymodel>localhost:8099/api/v1/capability/list/

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>spring-boot-unittest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-boot-unittest</name>
    <description>Demo project for Spring Boot unit test</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-hateoas</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-mongodb</artifactId>
        </dependency>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-mongodb</artifactId>
            <version>4.1.4</version>
        </dependency>

        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-apt</artifactId>
            <version>4.1.4</version>
        </dependency>
        <!-- Embedded  MongoDB for Testing -->
        <dependency>
            <groupId>de.flapdoodle.embed</groupId>
            <artifactId>de.flapdoodle.embed.mongo</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-ui</artifactId>
            <version>1.2.21</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.mysema.maven</groupId>
                <artifactId>apt-maven-plugin</artifactId>
                <version>1.1.3</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>process</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>target/generated-sources/java</outputDirectory>
                            <!--<processor>com.querydsl.mongodb.morphia.MorphiaAnnotationProcessor</processor>-->
                            <processor>org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor</processor>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

控制器.java

@RestController
@RequestMapping(value = "/api/v1/capability")
@RequiredArgsConstructor
@CrossOrigin
public class CapabilityController {

    private final CapabilityService capabilityService;
    private final CapabilityResourceAssembler capabilityResourceAssembler;

    @GetMapping(value = "/list")
    public CollectionModel<EntityModel<Capability>> getAllCapabilities() {
       List<EntityModel<Capability>> capabilities = capabilityService.listCapabilities().stream()
               .map(capability -> new EntityModel<>(capability,
                       linkTo(methodOn(CapabilityController.class).getCapabilityById(capability.getId())).withRel("getThisCapability"),
                       linkTo(methodOn(CapabilityController.class).getAllCapabilities()).withRel("getAllCapabilities")
               )).collect(Collectors.toList());
        return new CollectionModel<>(capabilities);
    }
}

实际响应

{
  "_embedded": {
    "capabilityList": [
      {
        "id": "sample",
        "techStack": "Java",
        "numOfDevelopers": 25,
        "numOfAvailableDevelopers": 10,
        "_links": {
          "getThisCapability": {
            "href": "http://localhost:8099/api/v1/capability/sample"
          },
          "getAllCapabilities": {
            "href": "http://localhost:8099/api/v1/capability/list"
          },
          "deleteThisCapability": {
            "href": "http://localhost:8099/api/v1/capability/sample"
          },
          "createCapability": {
            "href": "localhost:8099/api/v1/capability"
          }
        }
      }
    ]
  }
}

预期响应:

[
  {
    "id": "sample",
    "techStack": "Java",
    "numOfDevelopers": 25,
    "numOfAvailableDevelopers": 10,
    "_links": {
      "getThisCapability": {
        "href": "http://localhost:8099/api/v1/capability/sample"
      },
      "getAllCapabilities": {
        "href": "http://localhost:8099/api/v1/capability/list"
      }
    }
  }
]

我试过了
spring.data.rest.defaultmediatype=应用程序/json
spring.hateoas.use hal作为默认的json媒体类型=false
但我还是看不见运气 _embedded 响应中的属性。有谁能帮我找出这个问题吗。
我用的是 spring-boot-1.5.10 在此之前,我可以渲染链接没有正确的 _embedded ,请参阅此处。
在我在主类中添加了下面的注解之后,如果我返回列表,它就可以正常工作了
@enablehypermediasupport(type=enablehypermediasupport.hypermediatype.hal)
localhost:9771/api/v1/capability/list
这将产生以下结果:

[
  {
    "capabilityId": "sample",
    "techStack": "Java",
    "numOfDevelopers": 25,
    "numOfAvailableDevelopers": 10,
    "_links": {
      "getThisCapability": {
        "href": "http://localhost:9771/api/v1/capability/sample"
      },
      "getAllCapabilities": {
        "href": "http://localhost:9771/api/v1/capability/list"
      }
    }
  }
]

不幸的是,它在最新版本中不起作用。任何帮助都将不胜感激。

ukxgm1gy

ukxgm1gy1#

当使用SpringBoot1.5时,您依赖于SpringHateOAS的限制,这导致了jackson ObjectMapper 作为应用程序范围使用的特定于hal的 ObjectMapper . 这种污染意味着hal格式应用于本不该应用的响应。
springhateoas1.0及其特定的hal解决了这个限制 ObjectMapper 不再污染整个应用程序。如果你想要主应用程序 ObjectMapper 要应用hal样式的序列化,您可以通过定制选择重新加入:

@Bean
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder,
                                 HypermediaMappingInformation mappingInformation) {
    ObjectMapper objectMapper = builder.build();
    mappingInformation.configureObjectMapper(objectMapper);
    return objectMapper;
}

虽然我认为上述方法会奏效,但我将回应daniel在回答中提出的关于响应格式和hal规范合规性的问题。

tnkciper

tnkciper2#

如果我正确理解了hal规范,那么这将是无效的hal,这就是为什么只要返回 CollectionModel 在你的请求中。请注意,集合也可能有链接,链接将位于 _embedded a中的属性 _links 属性,如本示例文档中所述。
万一你真的想摆脱 _embedded 属性并生成 EntityModel<T> s、 如果您修改代码以返回 List<EntityModel<Capability>> . 你将失去 _embedded 以及 _links 由spring hateoas生成的属性。以下是修改后的代码段:

@RestController
@RequestMapping(value = "/api/v1/capability")
@RequiredArgsConstructor
@CrossOrigin
public class CapabilityController {

    private final CapabilityService capabilityService;
    private final CapabilityResourceAssembler capabilityResourceAssembler;

    @GetMapping(value = "/list")
    public List<EntityModel<Capability>> getAllCapabilities() {
       List<EntityModel<Capability>> capabilities = capabilityService.listCapabilities().stream()
               .map(capability -> new EntityModel<>(capability,
                       linkTo(methodOn(CapabilityController.class).getCapabilityById(capability.getId())).withRel("getThisCapability"),
                       linkTo(methodOn(CapabilityController.class).getAllCapabilities()).withRel("getAllCapabilities")
               )).collect(Collectors.toList());
        return capabilities;
    }
}

我强烈建议不要这样做,因为你失去了春夏节的优势。
此外,我建议利用你的 CapabilityResourceAssembler 创建 EntityModel<Capability> 通过使用 capabilityResourceAssembler.toModel(...) 因此,您不必重复您在应用程序中实现的代码 .map(...) 功能。

相关问题