- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 Spring Boot 2、Spring Data REST、Spring HATEOAS 创建一个 Spring REST 应用。
我创建了这个 Controller :
@Api(tags = "City Entity")
@RepositoryRestController
@RequestMapping(path = "/api/v1")
@PreAuthorize("isAuthenticated()")
public class CityController {
@Autowired
private LocalValidatorFactoryBean validator;
@Autowired
private PagedBeanResourceAssembler<City> pagedBeanResourceAssembler;
@Autowired
private CityService cityService;
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(validator);
}
@GetMapping(path = "/cities/search/autocomplete")
public ResponseEntity<?> autocomplete(@RequestParam(name = "city") String city, @RequestParam(name = "country", required = false) String country, Pageable pageable, Locale locale) {
return new ResponseEntity<>(pagedBeanResourceAssembler.toResource(cityService.autocomplete(city, country, pageable)), HttpStatus.OK);
}
}
服务方式为:
@Transactional(readOnly = true)
public Page<City> autocomplete(String text, String country, Pageable pageable) {
//my logic
return elasticSearchManager.search(ElasticSearchUtil.getIndexName(City.class), null, City.class, filters, null, pageable);
}
如您所见,City bean 未存储在数据库中。事实上,bean 是:
public class City implements Persistable<Long> {
private Long id;
@NotBlank
private String name;
private String district;
private String region;
private String zipCode;
@NotNull
@Size(min = 2, max = 2)
private String country;
}
最后这是我的 PagedBeanResourceAssembler
:
@Component
public class PagedBeanResourceAssembler<T> implements ResourceAssembler<Page<T>, PagedResources<T>> {
@Autowired
private EntityLinks entityLinks;
@Override
public PagedResources<T> toResource(Page<T> page) {
PagedResources<T> pagedResources = new PagedResources<T>(page.getContent(), asPageMetadata(page));
return pagedResources;
}
private PagedResources.PageMetadata asPageMetadata(Page<?> page) {
Assert.notNull(page, "Page must not be null!");
return new PagedResources.PageMetadata(page.getSize(), page.getNumber(), page.getTotalElements(), page.getTotalPages());
}
}
当我进行 http 调用时,我在控制台中看到一条警告消息:
08/02/2019 11:09:35,526 WARN http-nio-8082-exec-1 RepositoryRestMvcConfiguration$ResourceSupportHttpMessageConverter:205 - Failed to evaluate Jackson serialization for type [class org.springframework.hateoas.PagedResources]: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.hateoas.hal.Jackson2HalModule$HalResourcesSerializer': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.hateoas.hal.Jackson2HalModule$HalResourcesSerializer]: No default constructor found; nested exception is java.lang.NoSuchMethodException: org.springframework.hateoas.hal.Jackson2HalModule$HalResourcesSerializer.<init>()
08/02/2019 11:09:35,527 WARN http-nio-8082-exec-1 MappingJackson2HttpMessageConverter:205 - Failed to evaluate Jackson serialization for type [class org.springframework.hateoas.PagedResources]: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.hateoas.hal.Jackson2HalModule$HalResourcesSerializer': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.hateoas.hal.Jackson2HalModule$HalResourcesSerializer]: No default constructor found; nested exception is java.lang.NoSuchMethodException: org.springframework.hateoas.hal.Jackson2HalModule$HalResourcesSerializer.<init>()
不使用 PagedResources 错误就消失了。我不明白我哪里做错了。我知道 HalResourcesSerializer
没有默认构造函数,但我没有直接使用它,我也不明白为什么 Entity 在数据库中持久存在这样一个 Controller ,这样工作正常。如何解决此问题并继续使用 PagedResource?
========更新==========
我添加我的配置以提供更详细的 View :
自定义配置:
@Configuration
@EnableRetry
@EnableTransactionManagement
@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
public class CustomConfiguration {
public static CustomConfiguration INSTANCE;
@PostConstruct
public void init() {
INSTANCE = this;
}
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
public static SpringSecurityAuditorAware springSecurityAuditorAware() {
return new SpringSecurityAuditorAware();
}
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasenames("classpath:/i18n/messages");
// messageSource.setDefaultEncoding("UTF-8");
// set to true only for debugging
messageSource.setUseCodeAsDefaultMessage(false);
messageSource.setCacheSeconds((int) TimeUnit.HOURS.toSeconds(1));
messageSource.setFallbackToSystemLocale(false);
return messageSource;
}
@Bean
public MessageSourceAccessor messageSourceAccessor() {
return new MessageSourceAccessor(messageSource());
}
/**
* Enable Spring bean validation https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#validation
*
* @return
*/
@Bean
public LocalValidatorFactoryBean validator() {
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
factoryBean.setValidationMessageSource(messageSource());
return factoryBean;
}
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
methodValidationPostProcessor.setValidator(validator());
return methodValidationPostProcessor;
}
/**
* Utility class from Google to work with phone numbers {@link https://github.com/googlei18n/libphonenumber}
*
* @return
*/
@Bean
public PhoneNumberUtil phoneNumberUtil() {
return PhoneNumberUtil.getInstance();
}
/**
* To enable SpEL expressions
*
* @return
*/
@Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
/**
* Define the specific storage manager to use (disk, S3, etc)
*
* @return
*/
@Bean
public StorageManager storageManager() {
return new S3StorageManager();
}
/**
* GRACEFUL SHUTDOWN
*/
@Bean
public GracefulShutdown gracefulShutdown() {
return new GracefulShutdown();
}
@Bean
public ConfigurableServletWebServerFactory webServerFactory(final GracefulShutdown gracefulShutdown) {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.addConnectorCustomizers(gracefulShutdown);
return factory;
}
}
GlobalRepositoryRestConfigurer:
@Configuration
public class GlobalRepositoryRestConfigurer implements RepositoryRestConfigurer {
private Logger log = LogManager.getLogger();
@Autowired(required = false)
private Jackson2ObjectMapperBuilder objectMapperBuilder;
@Autowired
private Validator validator;
@Value("${cors.mapping}")
private String corsMapping;
@Value("#{'${cors.allowed.headers}'.split(',')}")
private String[] corsAllowedHeaders;
@Value("#{'${cors.exposed.headers}'.split(',')}")
private String[] corsExposedHeaders;
@Value("#{'${cors.allowed.methods}'.split(',')}")
private String[] corsAllowedMethod;
@Value("#{'${cors.allowed.origins}'.split(',')}")
private String[] corsAllowedOrigins;
@Value("${cors.max.age}")
private int corsMaxAge;
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.getCorsRegistry().addMapping(corsMapping).exposedHeaders(corsExposedHeaders).allowedOrigins(corsAllowedOrigins)
.allowedHeaders(corsAllowedHeaders).allowedMethods(corsAllowedMethod).maxAge(corsMaxAge);
}
@Override
public void configureConversionService(ConfigurableConversionService conversionService) {
}
/**
* ValidationException serialiazer
*
* @return
*/
@Bean
public ValidationExceptionSerializer validationExceptionSerializer() {
return new ValidationExceptionSerializer();
}
@Bean
public CustomValidationExceptionSerializer customValidationExceptionSerializer() {
return new CustomValidationExceptionSerializer();
}
@Bean
public ConstraintViolationExceptionSerializer constraintViolationExceptionSerializer() {
return new ConstraintViolationExceptionSerializer();
}
/**
* Customize Object Mapper
*/
@Override
public void configureJacksonObjectMapper(ObjectMapper objectMapper) {
if (this.objectMapperBuilder != null) {
/**
* Custom serializer for ConstraintViolationException
* (https://jira.spring.io/browse/DATAREST-593)
*/
try {
SimpleModule constraintExceptionModule = new SimpleModule();
constraintExceptionModule.addSerializer(ConstraintViolationException.class, constraintViolationExceptionSerializer());
constraintExceptionModule.addSerializer(ValidationException.class, validationExceptionSerializer());
constraintExceptionModule.addSerializer(cloud.optix.server.exceptions.ValidationException.class, customValidationExceptionSerializer());
objectMapper.registerModule(constraintExceptionModule);
this.objectMapperBuilder.configure(objectMapper);
} catch (Exception e) {
log.error("", e);
}
}
}
@Override
public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
validatingListener.addValidator("beforeCreate", validator);
validatingListener.addValidator("beforeSave", validator);
}
@Override
public void configureExceptionHandlerExceptionResolver(ExceptionHandlerExceptionResolver exceptionResolver) {
}
/**
* Adding converter to donwload files in{@link org.springframework.web.bind.annotation.RestController}
*
* @param messageConverters
*/
@Override
public void configureHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
// super.configureHttpMessageConverters(messageConverters);
messageConverters.add(new ResourceHttpMessageConverter());
}
}
WebMvcConfiguration:
@Configuration
// Enable entity links for Spring HATEOAS
@EnableHypermediaSupport(type = {HypermediaType.HAL})
public class WebMvcConfiguration implements WebMvcConfigurer {
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private TenantRestClient tenantRestClient;
@Value("${cors.mapping}")
private String corsMapping;
@Value("#{'${cors.allowed.headers}'.split(',')}")
private String[] corsAllowedHeaders;
@Value("#{'${cors.exposed.headers}'.split(',')}")
private String[] corsExposedHeaders;
@Value("#{'${cors.allowed.methods}'.split(',')}")
private String[] corsAllowedMethod;
@Value("#{'${cors.allowed.origins}'.split(',')}")
private String[] corsAllowedOrigins;
@Value("${cors.max.age}")
private int corsMaxAge;
@Autowired
public WebMvcConfiguration() {
}
@Bean
public LocaleResolver localeResolver() {
return new SmartLocaleResolver();
}
public class SmartLocaleResolver extends CookieLocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest request) {
String acceptLanguage = request.getHeader("Accept-Language");
if (acceptLanguage == null || acceptLanguage.trim().isEmpty()) {
return super.determineDefaultLocale(request);
}
return request.getLocale();
}
}
/**
* Custom exception in WEB MVC
*
* @return
*/
@Bean
public CustomErrorAttributes myCustomErrorAttributes() {
return new CustomErrorAttributes();
}
/**
* Global CORS security configuration
*
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping(corsMapping).exposedHeaders(corsExposedHeaders).allowedOrigins(corsAllowedOrigins).allowedHeaders(corsAllowedHeaders)
.allowedMethods(corsAllowedMethod).maxAge(corsMaxAge);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TenantInterceptor());
}
}
最佳答案
尝试在您的配置中注释掉这一行:
this.objectMapperBuilder.configure(objectMapper);
我认为 RepositoryRestConfigurer 可以很好地为自身配置 objectMapper。
如果您需要它从类路径中自动添加更多模块,请手动添加/配置这些模块。
关于java - Spring HATEOAS HalResourcesSerializer 未找到默认构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54590203/
使用很棒的 HATEOAS 链接功能我正在尝试输出模板化的 url 以突出显示用户可用的过滤器参数 示例 Controller 方法 @RequestMapping(value = "/persons
我正在使用 spring-hateoas:0.18.0.RELEASE 与 spring-boot:1.2.5.RELEASE 为了调用我的 Web 服务并通过 HAL 链接,我正在使用 特拉弗森客户
我使用 Spring HATEOAS 在我的应用程序中创建 REST HATEOAS API。到目前为止它运行良好,但当涉及到嵌套资源时我陷入困境。将此类层次结构映射到 REST HATEOAS 资源
我想弄清楚如何使用 templated: true 建立 HAL 链接.如果我使用 BasicLinkBuilder.linkToCurrentMapping().slash("api/public/
我们使用 HATEOAS 取得了很好的效果,但是我们一直在关注性能,并且从链接的构建中得到了非常糟糕的结果,即看起来像这样的代码 resource.add(linkTo(methodOn(SomeCo
我有一个带有请求参数的方法,我正在尝试从另一个资源链接到这个方法。我希望链接是这样的: "rel":{ "href":".../resources{?param}", "templated":
我想链接到具有以下签名的方法: public SomeResponse getSomeObjects(@RequestParam(value = "foo", defaultValue = "bar"
我正在构建一个REST API。我有一个由bean组成的域模型,无法扩展ResourceSupport。使用Spring-HATEOAS将它们公开为资源的最佳方法是什么? 如果不可能,在bean生成的
我有这个问题已经在我的脑海里盘旋了一段时间。让我们假设我们已经在不同的层上构建了我们的项目,后端和前端。所以,从前端,我们想要一个客户,它来自 hal+json格式: GET /customers/1
我有一个关于 Spring HATEOAS 的表示模型处理器的问题。我们正在尝试在将模型序列化给客户端之前对其进行处理。我们的用例是丰富 imageUrl领域UserModel对象在运行时,因为我们必
想象一下,我有一个完全实现的REST API,它也提供了HATEOAS。 假设我浏览了根目录,除了自我链接之外,还返回了其他两个链接(例如,一个用于/users和一个用于/orders)。据我所知,H
据说在定义良好的 RESTful 系统中,客户端只需要知道根 URI 或几个众所周知的 URI,客户端将通过这些初始 URI 发现所有其他链接。我确实理解这种方法的好处(解耦客户端),但对我来说不利的
遵循 HATEOAS 原则,每个状态都应该是超链接的,对改变资源状态的链接进行建模的最佳方法是什么? 让我们以订单为例: { id : 12, state: 'pending', .
我试图对 HATEOAS 有一个清晰、简洁的理解,而且我绝不是 WRT REST 专家。 (我想我明白了,感谢这个 http://www.looah.com/source/view/2284 )。 有
我有理由相信我了解 HATEOAS 设计的服务器端 - 在响应中返回状态 URL - 但我对如何设计客户端来接受这些感到有点困惑。 例如,我们在//somehost.com/resource/1 访问
我正在阅读有关 spring-hateoas 的内容,看起来 1.0 有很多变化。我想切换到 1.0 但是我的 pom.xml 正在引入 0.25.2。 我试过用 org
我正在努力了解 HATEOAS。 让我们通过一个例子来工作。客户端将浏览器加载到 getemails.com。为简单起见,让我们假设对 getemails.com 的调用访问了服务器并返回一个电子邮件
我有 Spring Data Rest 和 Hateoas 作为我的支持。它在代理后面。 后端网址:backend.com 代理网址:proxy.com 当我查询代理网址时,例如http://prox
我可以有一些 HATEOAS 的示例/典型用例吗? ?我同意它可以是一个非常强大的概念,提供了很大的灵活性,但我不确定如何正确地从 HATEOAS 中受益。如果您可以分享您的经验/用例,那就太好了。
HATEOAS(作为应用程序状态引擎的超媒体)建议是否暗示查询字符串不是 RESTful? 编辑:下面建议查询字符串可能与状态没有太大关系,因此这个问题令人费解。我建议 URI 具有查询字符串没有意义
我是一名优秀的程序员,十分优秀!