编辑14/08/14 13:29
我的下一个结论是我的@RepositoryRestResource CrudRepository生成的hal + json格式不正确。
教程(http://spring.io/guides/gs/accessing-data-rest/)将超媒体Rest JPA实体的输出显示为:(请注意,没有“rel”元素,“links”不是数组)
{
"_links" : {
"people" : {
"href" : "http://localhost:8080/people{?page,size,sort}"
}
}
}
但是,参考文档(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"
}
}
有谁知道这是为什么?
=====================================
编辑2014年8月14日:我的调试更进了一步。通过提供我自己的org.springframework.hateoas.ResourceSupport类的实现,它检查json的“_links”而不是“链接”,我更进了一步。错误是:
“无法通过引用链从START_OBJECT令牌中反序列化java.util.ArrayList的实例....... com.ebs.solas.admin.test.SolicitorDTO [\”_ links \“]”
这是因为org.springframework.hateoas.ResourceSupport类似乎要求links属性是json数组。默认情况下,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
}
}
希望来自Spring论坛的人能在这里帮助我。
============================================== < / p>
请参阅我的Spring Data存储库代码概述:
@RepositoryRestResource
public interface SolicitorFirmRepository extends CrudRepository<SolicitorFirm, String> {
}
@Entity
@RestResource
@Table(name="XXXX", schema = "XXX")
public class SolicitorFirm implements Serializable {
}
这成功生成了以下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"
}
}
但是,当我为客户端/控制器使用定义DTO时:
import org.springframework.hateoas.ResourceSupport;
public class SolicitorFirmDTO extends ResourceSupport {
.....
}
并使用以下代码
RestTemplate rt = new RestTemplate();
String uri = new String("//xxxxx:9090/solas-admin-data-api/solicitors/Sxxxxx");
SolicitorFirmDTO u = rt.getForObject(uri, SolicitorFirmDTO.class, "SXXXX");
我收到以下错误:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:无法识别的字段“_links”(类com.ebs.solas.admin.test.SolicitorFirmDTO),未标记为可忽略(7个已知属性:xx))
由于某种原因,Spring Data Rest生成的json在_links
下添加实体链接,而HATEOAS资源超类期望links
?
任何人都可以帮忙吗?这是一个版本问题,还是需要一些额外的配置才能将_links
映射到links
我尝试MappingJackson2HttpMessageConverter
和各种媒体类型application/json+hal
无济于事。
答案 0 :(得分:1)
对于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;
}
答案 1 :(得分:1)
同时mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
在每个实体上使用@JsonIgnoreProperties(ignoreUnknown = true)
:
@Entity
@JsonIgnoreProperties(ignoreUnknown = true)
public class User {
...
}
答案 2 :(得分:0)
感谢您的回复。
回答你的问题,
1)我相信我的输入和输出都是HAL。您将从我的原始帖子中看到,从我的@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
}
}
}
但是引用链接在属性名称&#34; _links&#34;下,但客户端的RestSupport类似乎不期望任何_underscore,它似乎只搜索&#34;链接&#34 ;
2)是的,我已经指定了@EnableHypermediaSupport(type = HypermediaType.HAL),
请参阅下面我的完整配置如下(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();
}
}
我的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;
}
}
感谢您的帮助, appdJava