Как настроить Spring Data Rest для возврата типа носителя Json-LD или Siren вместо HAL - PullRequest
0 голосов
/ 27 августа 2018

Я изо всех сил пытался найти какие-либо примеры того, как можно переопределить стандартное поведение Spring Boot Data Rest JpaRepository, чтобы получить что-то отличное от ответа HAL.Я обнаружил, что и Siren, и Json-LD могут соответствовать требованиям, но не примеры того, как заставить его работать с пружиной.Я использую Spring 5, Spring Data Rest 2.0.4.RELEASE.Пожалуйста, обратите внимание, я не собираюсь делать это для настраиваемого контроллера остатка, но для репозитория по умолчанию, предоставляемого расширением JpaRepository.Это моя первая публикация, поэтому я прошу прощения за любые правила, которые я мог случайно нарушить.

Обновление: Мне удалось найти библиотеку Hydra-Spring с SirenMessageConverter, следуя примеру на репо, я смог сделать следующее:

@Configuration
@EnablePluginRegistries(RelProvider.class)

public class Config implements WebMvcConfigurer   {

private static final boolean EVO_PRESENT =
        ClassUtils.isPresent("org.atteo.evo.inflector.English", null);

@Autowired
private PluginRegistry<RelProvider, Class<?>> relProviderRegistry;

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(sirenMessageConverter());
    converters.add(hydraMessageConverter());
    converters.add(halConverter());
    converters.add(uberConverter());
    converters.add(xhtmlMessageConverter());
    converters.add(jsonConverter());
}

@Bean
public RepositoryRestConfigurerAdapter repositoryRestConfigurer() {

    return new RepositoryRestConfigurerAdapter() {

        @Override
        public void configureHttpMessageConverters(
              List<HttpMessageConverter<?>> messageConverters) {
            messageConverters.add(0, sirenMessageConverter());
        }

    };
}


@Bean
public HttpMessageConverter<?> uberConverter() {
    UberJackson2HttpMessageConverter converter = new UberJackson2HttpMessageConverter();
    converter.setSupportedMediaTypes(Collections.singletonList(HypermediaTypes.UBER_JSON));
    return converter;
}


private HttpMessageConverter<?> xhtmlMessageConverter() {
    XhtmlResourceMessageConverter xhtmlResourceMessageConverter = new XhtmlResourceMessageConverter();
    xhtmlResourceMessageConverter.setStylesheets(
            Arrays.asList(
                    "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css"
            ));
    xhtmlResourceMessageConverter.setDocumentationProvider(new JsonLdDocumentationProvider());
    return xhtmlResourceMessageConverter;
}

@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
    final ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
    resolver.setWarnLogCategory(resolver.getClass()
            .getName());
    exceptionResolvers.add(resolver);
}

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
  configurer.defaultContentType(HypermediaTypes.SIREN_JSON);
  }


@Bean
public HydraMessageConverter hydraMessageConverter() {
    return new HydraMessageConverter();
}

@Bean
public SirenMessageConverter sirenMessageConverter() {
    SirenMessageConverter sirenMessageConverter = new SirenMessageConverter();
    sirenMessageConverter.setRelProvider(new DelegatingRelProvider(relProviderRegistry));
    sirenMessageConverter.setDocumentationProvider(new JsonLdDocumentationProvider());
    sirenMessageConverter.setSupportedMediaTypes(Collections.singletonList(HypermediaTypes.SIREN_JSON));
    return sirenMessageConverter;
}


@Bean
public ObjectMapper jacksonObjectMapper() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
    return objectMapper;
}

@Bean
public MappingJackson2HttpMessageConverter jsonConverter() {
    MappingJackson2HttpMessageConverter jacksonConverter = new
            MappingJackson2HttpMessageConverter();
    jacksonConverter.setSupportedMediaTypes(Arrays.asList(MediaType.valueOf("application/json")));
    jacksonConverter.setObjectMapper(jacksonObjectMapper());
    return jacksonConverter;
}

@Bean
public CurieProvider curieProvider() {
    return new DefaultCurieProvider("ex", new UriTemplate("http://localhost:8080/webapp/hypermedia-api/rels/{rels}"));
}

@Bean
public MappingJackson2HttpMessageConverter halConverter() {
    CurieProvider curieProvider = curieProvider();

    RelProvider relProvider = new DelegatingRelProvider(relProviderRegistry);
    ObjectMapper halObjectMapper = new ObjectMapper();

    halObjectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);

    halObjectMapper.registerModule(new Jackson2HalModule());
    halObjectMapper.setHandlerInstantiator(new
            Jackson2HalModule.HalHandlerInstantiator(relProvider, curieProvider, null));

    MappingJackson2HttpMessageConverter halConverter = new
            MappingJackson2HttpMessageConverter();
    halConverter.setSupportedMediaTypes(Arrays.asList(MediaTypes.HAL_JSON));
    halConverter.setObjectMapper(halObjectMapper);
    return halConverter;
}

@Bean
RelProvider defaultRelProvider() {
    return EVO_PRESENT ? new EvoInflectorRelProvider() : new DefaultRelProvider();
}

@Bean
RelProvider annotationRelProvider() {
    return new AnnotationRelProvider();
}

}

Это мой текущий Pom.xml

    <?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.knowledgebase.DataRest</groupId>
    <artifactId>DataRest</artifactId>
    <version>2.1.0.M2</version>
    <packaging>jar</packaging>

    <name>DataRest</name>
    <description>Demo project for Spring Boot DataRest</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.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-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-hateoas</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.restdocs</groupId>
            <artifactId>spring-restdocs-mockmvc</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-rest-hal-browser</artifactId>
        </dependency>
        <dependency>
            <groupId>de.escalon.hypermedia</groupId>
            <artifactId>hydra-spring</artifactId>
            <version>0.4.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestones</id>
            <url>http://repo.spring.io/milestone</url>
        </pluginRepository>
    </pluginRepositories>


</project>

Однако это все равно не дает результатов, которые я ищу.Я знаю, что некоторые из изменений, которые я ввел в классе config, имеют значение, так как вывод теперь выглядит следующим образом:

{
"_embedded": {
"ex:contacts": []
},
"_links": {
"self": {
"href": "http://localhost:8080/contacts{?page,size,sort}",
"templated": true
},
"profile": {
"href": "http://localhost:8080/profile/contacts"
},
"search": {
"href": "http://localhost:8080/contacts/search"
},
"curies": [
{
"href": "http://localhost:8080/webapp/hypermedia-api/rels/{rels}",
"name": "ex",
"templated": true
}
]
},
"page": {
"size": 20,
"totalElements": 0,
"totalPages": 0,
"number": 0
}
}

Как вы можете видеть, поставщик Curries - единственное, что действительно работает.По какой-то причине при загрузке данных весенней загрузки JpaRepository не меняет тип приложения по умолчанию на SIREN_JSON, несмотря на:

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
  configurer.defaultContentType(HypermediaTypes.SIREN_JSON);
  }
...