I am using java in spring MVC framework for querying, my query is showing 600+ results but I only want the top 10 results.
This is what I have so far:
public interface ProductRepository extends SolrCrudRepository<Product, String>{
#Query("Product_Name:?0")
public List<Product> findByProductName(String productName);
}
Something like this should do the trick:
public interface ProductRepository extends SolrCrudRepository<Product, String>{
#Query("Product_Name:?0")
public List<Product> findByProductName(String productName, Pageable pageable); }
Then, call it like this:
PageRequest pageRequest = new PageRequest(0, 10);
myRepository.findByProductName("Product Name", pageRequest);
References:
Spring data - Special Parameters Handling
Spring Data - Page Request API
Related
I am currently developping a REST API server based on Spring Boot. Thanks to Spring Data Rest, the 10-ish entities can easily have their own controller via a simple repository (#RepositoryRestResource plus JpaRepository and JpaSpecificationExecutor). Now i need to integrate the security control with #PreAuthorize.
The question here is which method should I put the annotation on to restrain GET / POST / etc. ?
For example, if I limit the permission of delete, does it affect similarly on deleteById, deleteInBatch, deleteAll? I see in the documentation the annotation of exported is put on deleteById and delete without any further explanation, which confuses me.
For example, if I limit the permission of delete, does it affect similarly on deleteById, deleteInBatch, deleteAll?
To the best of my knowledge: no. Check this sample code where searches are authorized, but deletion is strictly limited to admins only:
public interface RecordRepository<T extends Record> extends MongoRepository<T, String> {
// paginated queries
#RestResource(path = "names", rel = "name")
public Page<T> findByName(#Param("name") String name, Pageable pageable);
#RestResource(path = "types", rel = "types")
public Page<T> findByTypeIn(#Param("type") List<String> types, Pageable pageable);
// restrict delete operations to administrators only
#PreAuthorize("hasRole('ADMIN')")
#Override
void deleteById(String id);
#PreAuthorize("hasRole('ADMIN')")
#Override
void delete(T entity);
#PreAuthorize("hasRole('ADMIN')")
#Override
void deleteAll(Iterable<? extends T> records);
#PreAuthorize("hasRole('ADMIN')")
#Override
void deleteAll();
}
That being said, if your purpose is to restrict deletion to admins only, you can extend WebSecurityConfigurerAdapter and configure it to block all http DELETE requests:
public class WebSecurityBaseConfiguration extends WebSecurityConfigurerAdapter {
...
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.DELETE).hasRole("ADMIN");
}
}
Note that this is a quick and dirty copy paste that may not work out of the box (you will probably need to configure a role hierarchy).
I am using Spring Boot 2 and I have write a #RestController within a #GetMapping that takes a Pageable as parameter.
#GetMapping
public ResponseEntity<Page<AppointmentTO>> findAll(Pageable pageable) {
Page<AppointmentTO> page = appointmentService.findAll(pageable);
return ResponseEntity.ok(page);
}
The problem is the following:
By each request, the queries-parameters pageSize and offset are always reset to default when they arrived in Spring Boot Backend (?offset=0&pageSize=20), however I send different parameters in the url of my request (?offset=15&pageSize=5 for example).
Spring Boot maps the request params to org.springframework.data.domain.PageRequest that extends AbstractPageRequest
AbstractPageRequest implements Pageable, Serializable {
...
private final int page;
private final int size;
public long getOffset() {
return (long)this.page * (long)this.size;
}
...
You should use following url:
http://localhost:8080?page=3&size=5
Also you could add sorting by ...&sort=name
I'd like to create my own custom Spring Data JPA find method that takes Integer, Specification and Pageable.
I've tried creating method like
Page<Student> findAllByGroupId(Integer id, Specification<Student> specification, Pageable pageable);
But it doesn't work.
User Repository
#Repository
public interface UserRepository<T extends User> extends PagingAndSortingRepository<T, Integer>,
JpaSpecificationExecutor<T> {
}
Student Repository
#Repository
public interface StudentRepository extends UserRepository<Student>{
Page<Student> findAllByGroupId(Integer id, Specification<Student> specification, Pageable pageable);
}
Service
#Override
public Page<Student> getGroupStudents(Integer id, StudentQuery studentQuery, Pageable pageable) {
Specification<Student> specification =
studentSpecification.getSpecification(studentQuery);
return studentRepository.findAllByGroupId(id, specification, pageable);
}
When I try this I get
java.lang.IllegalArgumentException: At least 2 parameter(s) provided but only 1 parameter(s) present in query.
Is there any way to create custom find method that takes Integer, Specification and Pageable?
I am trying to get page with a number of items in each page. For some reason, this method returns the complete list instead of page of 5 items.
public Page<Item> searchPagedCategoryByName(#RequestParam String name)
{
Category category;
category = categoryRepository.findCategoryByCategoryName(name);
List<Item> items = category.getItems();
Pageable pageable = PageRequest.of(0,5);
Page<Item> page = new PageImpl<Item>(items, pageable, items.size());
return page;
}
Create the repository extending PagingAndSortingRepository which provides perform pagination and sorting capability and then you can use like this,
Here is a code snippet from my practice workspace.
public interface CategoryRepository extends PagingAndSortingRepository< Category, Long> {
List<Category> findCategoryByCategoryName(String categoryName, Pageable pageable);
}
#Bean
public CommandLineRunner pagingAndSortingRepositoryDemo(CategoryRepository repository) {
return (args) -> {
log.info("Category found with Paging Request PageRequest.of(page [zeroBased Page index], Size)");
repository. findCategoryByCategoryName(name , PageRequest.of(0, 5)).forEach(category -> log.info(" :=> " + category));
};
}
I'm trying to implement a controller method similar to how is documented in the latest Gosling release train of Spring Data that supports QueryDsl. I've implemented the controller as shown in the example in the docs at http://docs.spring.io/spring-data/jpa/docs/1.9.0.RELEASE/reference/html/#core.web.type-safe. Everything compiles and when I start the application (using Spring Boot 1.2.5.RELEASE), everything starts fine.
However, when I try to call my rest endpoint, I always get the following exception:
org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.mysema.query.types.Predicate]: Specified class is an interface
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:101)
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.createAttribute(ModelAttributeMethodProcessor.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttribute(ServletModelAttributeMethodProcessor.java:80)
My guess is that the QuerydslPredicateArgumentResolver is not being applied to the request, and thus the exception. But I see that the QuerydslPredicateArgumentResolver is registered as a bean when I query the Spring Boot manage endpoint /manage/beans. I have also ensured that #EnableSpringDataWebSupport is on my #Configuration class to no effect.
I have the controller annotated with #BasePathAwareController, since I'm using this with Spring Data REST and I want the methods to be under a similar path as the ones that Spring Data REST exposes. I also tried using #RepositoryRestController, but that didn't seem to matter. However, when using #RestController and putting it under a path that was different then the base path that Spring Data REST is using, things worked. So the question is, should it work?
The entire controller right now is:
#RestController
#RequestMapping(value = "/query")
public class AvailController
{
private final AvailRepository repo;
#Autowired
public AvailController(AvailRepository repository)
{
this.repo = repository;
}
#RequestMapping(value = "/avails", method = GET)
public #ResponseBody Page<Avail> getAvails(Model model,
#QuerydslPredicate(root = Avail.class) Predicate predicate,
Pageable pageable,
#RequestParam MultiValueMap<String, String> parameters)
{
return repo.findAll(predicate, pageable);
}
}
I had the same problem with instantiation of Predicate. In the example:
#Controller
#RequiredArgsConstructor(onConstructor = #__(#Autowired) )
class UserController {
private final UserRepository repository;
#RequestMapping(value = "/", method = RequestMethod.GET)
String index(Model model, //
#QuerydslPredicate(root = User.class) Predicate predicate, //
#PageableDefault(sort = { "lastname", "firstname" }) Pageable pageable, //
#RequestParam MultiValueMap<String, String> parameters) {
(...)
(https://github.com/spring-projects/spring-data-examples/blob/master/web/querydsl/src/main/java/example/users/web/UserController.java#L42 ) is using just #Controller and I was using #RepositoryRestController, that seems to be the reason. #RestController also works for me.
I created https://jira.spring.io/browse/DATAREST-838
I also had this issue when trying to implement a custom controller that mimics the returned value as Spring Data REST. I wanted to inject QuerydslPredicate to the controller method and got the annoying 'BeanInstantiationException'.
I found a work around for this by adding the following configuration file to my application:
#Configuration
#Order(Ordered.HIGHEST_PRECEDENCE )
public class MvcConfig extends WebMvcConfigurerAdapter {
#Autowired
#Qualifier("repositoryExporterHandlerAdapter")
RequestMappingHandlerAdapter repositoryExporterHandlerAdapter;
#Override
public void addArgumentResolvers(
List<HandlerMethodArgumentResolver> argumentResolvers) {
List<HandlerMethodArgumentResolver> customArgumentResolvers = repositoryExporterHandlerAdapter.getCustomArgumentResolvers();
argumentResolvers.addAll(customArgumentResolvers);
}
}
See here for reference: https://jira.spring.io/browse/DATAREST-657