简体   繁体   English

Spring Data Rest - _links

[英]Spring Data Rest - _links

Edit 14/08/14 13:29 编辑14/08/14 13:29

My next conclusion is that the hal+json format produced from my @RepositoryRestResource CrudRepository is incorrect. 我的下一个结论是我的@RepositoryRestResource CrudRepository生成的hal + json格式不正确。

The tutorial ( http://spring.io/guides/gs/accessing-data-rest/ ) shows the output of a hypermedia Rest JPA entity as: (please note there is no "rel" element, and "links" is not an array) 教程( http://spring.io/guides/gs/accessing-data-rest/ )将超媒体Rest JPA实体的输出显示为:(请注意,没有“rel”元素,“links”不是数组)

{
   "_links" : {
       "people" : {
           "href" : "http://localhost:8080/people{?page,size,sort}"
       }
   }
 }

However, the reference docs ( http://docs.spring.io/spring-data/rest/docs/1.1.x/reference/html/intro-chapter.html ) show that the output should be: 但是,参考文档( http://docs.spring.io/spring-data/rest/docs/1.1.x/reference/html/intro-chapter.html )显示输出应为:

{
    "links" : [ {
        "rel" : "customer",
        "href" : "http://localhost:8080/customer"
      }, {
         "rel" : "profile",
         "href" : "http://localhost:8080/profile"
      }
 }

Does anyone know why this is? 有人知道为什么吗?

===================================== =====================================

Edit 14/08/14: I have taken my debugging a step further. 编辑2014年8月14日:我的调试更进了一步。 By providing my own implementation of a org.springframework.hateoas.ResourceSupport class, which inspects the json for "_links" rather than "links" I get a step further. 通过提供我自己的org.springframework.hateoas.ResourceSupport类的实现,它检查json的“_links”而不是“链接”,我更进了一步。 The error is: 错误是:

"Can not deserialize instance of java.util.ArrayList out of START_OBJECT token ..... through reference chain: com.ebs.solas.admin.test.SolicitorDTO[\\"_links\\"]" “无法通过引用链从START_OBJECT标记中反序列化java.util.ArrayList的实例..... com.ebs.solas.admin.test.SolicitorDTO [\\”_ links \\“]”

This is because the org.springframework.hateoas.ResourceSupport class seems to require that the links attribute be a json array. 这是因为org.springframework.hateoas.ResourceSupport类似乎要求links属性是json数组。 And by default the json+hal output produced by Spring Data for a Rest Entity does not produce an array (there are no square brackets): 默认情况下,Spring Data为Rest Entity生成的json + hal输出不会生成数组(没有方括号):

"_links" : {
  "self" : {
    "href" : "http://localhost:9090/solas-admin-data-api/solicitorFirms/Fxxx"
  },
  "solicitors" : {
    "href" : "http://localhost:9090/solas-admin-data-api/solicitorFirms/Fxxx/solicitor
  }
}

Hopefully someone from the Spring forums could help me here. 希望来自Spring论坛的人能在这里帮助我。

============================================== ==============================================

please see an outline of my Spring Data repository code: 请查看我的Spring Data存储库代码的概述:

@RepositoryRestResource
    public interface SolicitorFirmRepository extends CrudRepository<SolicitorFirm, String> {
}

@Entity
@RestResource
@Table(name="XXXX", schema = "XXX")
public class SolicitorFirm implements Serializable {
}

This successfully generates the following hateoas resource: 这成功生成了以下hateoas资源:

{
"firmNumber" : "FXXXX",
"solicitorType" : "r",
"companyName" : "XXXX",
"address1" : "XXXX",
"address2" : "XXX",
"address3" : "XXX",
"address4" : null,
"phoneNumber" : "XXXXX",
"faxNumber" : "XXXXX",
"county" : "OY",
"_links" : {
    "self" : {
        "href" : "http://localhost:9090/solas-admin-data-api/solicitorFirms/XXXX"
    },
    "solicitors" : {
        "href" : "http://localhost:9090/solas-admin-data-api/solicitorFirms/XXXX/solicitors"
    }
 }

HOWEVER, when i define a DTO for clientside/controller use: 但是,当我为客户端/控制器使用定义DTO时:

import org.springframework.hateoas.ResourceSupport;
public class SolicitorFirmDTO extends ResourceSupport {
   .....
}

and use the following code 并使用以下代码

RestTemplate rt = new RestTemplate();
String uri = new String("//xxxxx:9090/solas-admin-data-api/solicitors/Sxxxxx");
SolicitorFirmDTO u = rt.getForObject(uri, SolicitorFirmDTO.class, "SXXXX");

I get the following error: 我收到以下错误:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "_links" (class com.ebs.solas.admin.test.SolicitorFirmDTO), not marked as ignorable (7 known properties: xx]) com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:无法识别的字段“_links”(类com.ebs.solas.admin.test.SolicitorFirmDTO),未标记为可忽略(7个已知属性:xx))

For some reason the json produced by Spring Data Rest adds the entity links under _links while the HATEOAS resource superclass expects links ? 出于某种原因,Spring Data Rest生成的json在_links下添加实体链接,而HATEOAS资源超类需要links

Can any one help? 任何人都可以帮忙吗? is this a version issue or do I need some extra configuration to map _links to links 这是一个版本问题还是我需要一些额外的配置来将_links映射到links

I have tried MappingJackson2HttpMessageConverter and various media types application/json+hal to no avail. 我已经尝试过MappingJackson2HttpMessageConverter和各种媒体类型application/json+hal无济于事。

For Spring-boot 1.3.3 the method exchange() for List is working 对于Spring-boot 1.3.3, List的方法exchange()正在工作

public void test1() {

    RestTemplate restTemplate = restTemplate();

    ParameterizedTypeReference<PagedResources<User>> responseTypeRef = new ParameterizedTypeReference<PagedResources<User>>() {
    };

    String API_URL = "http://localhost:8080/api/v1/user"
    ResponseEntity<PagedResources<User>> responseEntity = restTemplate.exchange(API_URL, HttpMethod.GET,
            (HttpEntity<User>) null, responseTypeRef);

    PagedResources<User> resources = responseEntity.getBody();
    Collection<User> users = resources.getContent();
    List<User> userList = new ArrayList<User>(users);

    System.out.println(userList);

}

private RestTemplate restTemplate() {

    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    mapper.registerModule(new Jackson2HalModule());

    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
    converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json"));
    converter.setObjectMapper(mapper);

    List<HttpMessageConverter<?>> converterList = new ArrayList<HttpMessageConverter<?>>();
    converterList.add(converter);
    RestTemplate restTemplate = new RestTemplate(converterList);

    return restTemplate;
}

Also with mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) use @JsonIgnoreProperties(ignoreUnknown = true) on every Entity: 另外使用mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) @JsonIgnoreProperties(ignoreUnknown = true)在每个实体上使用@JsonIgnoreProperties(ignoreUnknown = true)

@Entity
@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
    ...

}

thanks for your response. 感谢您的答复。

In answer to your questions, 在回答你的问题时,

1) I believe that my input and output are both HAL. 1)我相信我的输入和输出都是HAL。 You will see from my original post that the json produced from my @RepositoryRestResource is HAL (notice it contains ref links to itself and associated entities): 您将从我的原始帖子中看到,从我的@RepositoryRestResource生成的json是HAL(请注意它包含指向自身和关联实体的ref链接):

{
  "firmNumber" : "Fxx",
  "solicitorType" : "r",
  "companyName" : "xxx",
  "address1" : "xxx,",
  "address2" : "xx,",
  "address3" : "xxx,",
  "_links" : {
      "self" : {
         "href" : "http://localhost:9090/solas-admin-data-api/solicitorFirms/Fxx"
      },
      "solicitors" : {
         "href" : "http://localhost:9090/solas-admin-data-api/solicitorFirms/Fxx/solicitors
     }
  }
}

However the reference links are under the attribute name "_links", but the RestSupport class on the client side does not seem to expect any _underscore, it only seems to search for "links" 但是引用链接在属性名称“_links”下,但是客户端上的RestSupport类似乎不期望任何_underscore,它似乎只搜索“链接”

2) yes i have specified @EnableHypermediaSupport(type = HypermediaType.HAL), 2)是的,我已经指定了@EnableHypermediaSupport(type = HypermediaType.HAL),

please see below for my full configuration is as follows (javaconfig): 请看下面我的完整配置如下(javaconfig):

@Configuration
@ComponentScan("com.ebs.solas.admin")
@EnableJpaRepositories("com.ebs.solas.admin")
@EnableTransactionManagement
@Import(RepositoryRestMvcConfiguration.class)
class ApplicationConfig {

    @Bean
    public DataSource dataSource() {

          DriverManagerDataSource dataSource = new DriverManagerDataSource();
          dataSource.setDriverClassName("com.ibm.db2.jcc.DB2Driver");
          dataSource.setUrl("jdbc:db2://xxxx:52001/xxxx");
          dataSource.setUsername( "xxx" );
          dataSource.setPassword( "xxx" );
          return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setDatabase(Database.DB2);
        vendorAdapter.setGenerateDdl(false);
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan("com.ebs.solas.admin");
        factory.setDataSource(dataSource());
        return factory;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return txManager;
    }
}


public class RestWebApplicationInitializer implements WebApplicationInitializer { 

    public void onStartup(ServletContext context) throws ServletException {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(ApplicationConfig.class);

        context.addListener(new ContextLoaderListener(rootContext));

        RepositoryRestDispatcherServlet exporter = new RepositoryRestDispatcherServlet();
        ServletRegistration.Dynamic reg = context.addServlet("exporter", exporter);
        reg.setLoadOnStartup(1);
        reg.addMapping("/*");
    }
}


@Configuration
@ComponentScan("com.ebs.solas.admin")
@EnableWebMvc
@EnableHypermediaSupport(type = HypermediaType.HAL)
class WebMVCConfiguration extends WebMvcConfigurationSupport {

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer c) {
        c.defaultContentType(MediaType.APPLICATION_JSON);
    }

    @Bean
    public MultipartResolver multipartResolver() { 
        return new StandardServletMultipartResolver();
    }
}

My RestController also specifies that the RestTemplate should use hal+json message conversion format, see below 我的RestController还指定RestTemplate应该使用hal + json消息转换格式,见下文

@RestController
public class TestController {

     @RequestMapping(value="/test", method=RequestMethod.GET, produces={"application/hal+json"})
     @ResponseStatus(HttpStatus.OK)
     public SolicitorDTO doTest() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new Jackson2HalModule());

        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
         converter.setSupportedMediaTypes(org.springframework.http.MediaType.parseMediaTypes("application/hal+json"));
        converter.setObjectMapper(mapper);

        RestTemplate rt = new RestTemplate();
        rt.getMessageConverters().add(converter);


        String uri = new String("http://localhost:9090/solas-admin-data-api/solicitors/{id}");
        SolicitorDTO u = rt.getForObject(uri, SolicitorDTO.class, "Sxxxxx");
        return u;
     }   
}

Thanks for your help, appdJava 感谢您的帮助,appdJava

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM