我正在尝试在Spring Boot中为我的Spring Data JPA存储库实现分页,但是在运行uni测试时我遇到了以下异常:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.domain.Pageable]: Specified class is an interface
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
...
有人能指出我在这里错过了什么吗?这是我的存储库:
@Repository
public interface VenueRepository extends PagingAndSortingRepository<Venue, Long> {
public Page<Venue> findAll(Pageable pageable);
}
和控制器:
@RestController
@RequestMapping("/venues")
public class VenueController {
@Autowired
private VenueRepository venueRepo;
@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Page<Venue>> getVenues(Pageable pageable) {
return new ResponseEntity<>(venueRepo.findAll(pageable), HttpStatus.OK);
}
}
最后我的测试:
@Test
public void responseOkVenuesTest() throws Exception {
mvc.perform(get("/venues").accept(MediaType.APPLICATION_JSON_VALUE)).andExpect(status().isOk());
}
我花了几个小时试图完成这项工作,但我的想法已经不多了。感谢您的任何提示!
答案 0 :(得分:3)
以您传递参数的方式更改方法getVenues
,以实例化PageRequest
而不是传递Pageable
:
@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<List<Venue>> getVenues(int from,int to) {
return new ResponseEntity<>(
venueRepo.findAll((new PageRequest(from, to)), HttpStatus.OK).getContent();
}
答案 1 :(得分:0)
除了@ SEY_91之外,您还可以使用以下How to remove redundant Spring MVC method by providing POST-only @Valid?启发的解决方案,并在我的Spring Boot驱动的应用程序中使用了很长时间。
简而言之,这是一个注释控制器方法参数的注释:
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface PlainModelAttribute {
}
现在,只是一个方法处理器,它将扫描用@PlainModelAttribute
注释的参数:
public final class PlainModelAttributeMethodProcessor
extends ModelAttributeMethodProcessor {
private final Map<TypeToken<?>, Converter<? super NativeWebRequest, ?>> index;
private PlainModelAttributeMethodProcessor(final Map<TypeToken<?>, Converter<? super NativeWebRequest, ?>> index) {
super(true);
this.index = index;
}
public static HandlerMethodArgumentResolver plainModelAttributeMethodProcessor(final Map<TypeToken<?>, Converter<? super NativeWebRequest, ?>> index) {
return new PlainModelAttributeMethodProcessor(index);
}
@Override
public boolean supportsParameter(final MethodParameter parameter) {
return parameter.hasParameterAnnotation(PlainModelAttribute.class) || super.supportsParameter(parameter);
}
@Override
protected Object createAttribute(final String attributeName, final MethodParameter parameter, final WebDataBinderFactory binderFactory,
final NativeWebRequest request) {
final TypeToken<?> typeToken = TypeToken.of(parameter.getGenericParameterType());
final Converter<? super NativeWebRequest, ?> converter = index.get(typeToken);
if ( converter == null ) {
throw new IllegalArgumentException("Cannot find a converter for " + typeToken.getType());
}
return converter.convert(request);
}
@Override
protected void bindRequestParameters(final WebDataBinder binder, final NativeWebRequest request) {
final HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
if ( !isSafe(resolve(servletRequest.getMethod())) ) {
((ServletRequestDataBinder) binder).bind(servletRequest);
}
}
private static HttpMethod resolve(final String name) {
return HttpMethod.valueOf(name.toUpperCase());
}
private static boolean isSafe(final HttpMethod method)
throws UnsupportedOperationException {
switch ( method ) {
case GET:
case HEAD:
case OPTIONS:
return true;
case POST:
case PUT:
case PATCH:
case DELETE:
return false;
case TRACE:
throw new UnsupportedOperationException();
default:
throw new AssertionError(method);
}
}
}
我真的不记得了,但是Spring Framework中的某个resolve()
方法应该存在。请注意,我使用Google Guava TypeToken是为了让处理器与泛型类型兼容(因为我在控制器中使用IQuery<Foo>
和IQuery<Bar>
等模型。现在只需注册处理器:
@Configuration
@EnableWebMvc
public class MvcConfiguration
extends WebMvcConfigurerAdapter {
@Override
public void addArgumentResolvers(final List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(createModelAttributeMethodProcessor());
}
private static HandlerMethodArgumentResolver createModelAttributeMethodProcessor() {
return plainModelAttributeMethodProcessor(ImmutableMap.of(pageableTypeToken, MvcConfiguration::toPageable));
}
private static final TypeToken<Pageable> pageableTypeToken = new TypeToken<Pageable>() {
};
private static Pageable toPageable(final WebRequest request) {
return new PageRequest(
ofNullable(request.getParameter("page")).map(Integer::parseInt).orElse(0),
ofNullable(request.getParameter("size")).map(Integer::parseInt).orElse(1)
);
}
}
这是对Pageable
DTO转换的Web请求,转换器必须注册为参数解析器。所以现在可以使用了:
@RestController
@RequestMapping("/")
public class Controller {
@RequestMapping(method = GET)
public String get(@PlainModelAttribute final Pageable pageable) {
return toStringHelper(pageable)
.add("offset", pageable.getOffset())
.add("pageNumber", pageable.getPageNumber())
.add("pageSize", pageable.getPageSize())
.add("sort", pageable.getSort())
.toString();
}
}
一些例子:
/
⇒PageRequest{offset=0, pageNumber=0, pageSize=1, sort=null}
/?page=43
⇒PageRequest{offset=43, pageNumber=43, pageSize=1, sort=null}
/?size=32
⇒PageRequest{offset=0, pageNumber=0, pageSize=32, sort=null}
/?page=22&size=32
⇒PageRequest{offset=704, pageNumber=22, pageSize=32, sort=null}