Поиск с полями Mutliple и реализация нумерации страниц в Springboot - PullRequest
1 голос
/ 10 января 2020

У меня есть следующий requestDto и контроллер

@PostMapping 
public responseDto search(@RequestBody SearchUserRequestDto request){
    userService.search(request);
}
public class SearchUserRequestDto {

    private Long userId;
    private String firstName;
    private String lastName;
    private String role;
    private String userType;
}

Я хочу выполнить поиск в хранилище пользователя с полями, которые не равны нулю выше Dto.

Пример : Если firstName равно "john" , а lastName равно "smith" , а остальные поля пусты, то мне нужно найти в хранилище все записи WHERE firstName - "Джон" И lastName - "Смит" (Не ИЛИ )

У меня также есть реализовать нумерацию страниц для ответа

Я новичок в Spring-Boot, кто-нибудь может подсказать мне, как это сделать?

Ответы [ 2 ]

2 голосов
/ 10 января 2020

По предложению @ mandar-dharurkar вы можете использовать org.springframework.data.domain.Pageable, но для условного поиска вы используете что-то вроде ниже,

@Query("SELECT u FROM User u WHERE (:name is null or u.name = :name) and (:lastname is null"
  null + " or u.lastname= :lastname)")
Page<User> search(@Param("name") String name, @Param("lastname") String lastname, Pageable pageable);
1 голос
/ 10 января 2020

Если вы используете JPA, я рекомендую использовать Spring Data JPA и API спецификации . Когда я впервые взглянул на Spring Boot и Spring Data, единственным реальным подходом, который я увидел, был продвинутый Spring Data Rest, который на мой вкус был слишком волшебным c.

Лично мне нравится, когда контроллеры вызывают методы в сервисах (многократно используемый слой бизнес-логики c, который в основном является шаблоном Facade). Эти сервисы в конечном итоге вызывают репозитории Spring Data.

Рассмотрим объект User

public class User{
  String firstName;
  String lastName;
}

Допустим, у нас есть UserController, обрабатывающий наши REST-запросы для ресурса User. Этот контроллер преобразует запрос с UserSearchCriteria в данные Spring Page<User>

import org.springframework.data.domain.Page;

public class UserController{

  @Autowired
  UserService userService;

  @RequestMapping(path = "/users", method = RequestMethod.GET)
  Page<User> getAll(HttpServletRequest request, UserSearchCriteria searchCriteria){
     return userService.findAllUsers(searchCriteria);
  }
}

UserSearchCriteria - это типы поисковых параметров, которые ваш клиент передает в виде параметров запроса, таких как GET /users?firstName=mista&lastName=henry, которые автоматически преобразуются в UserSearchCriteria поля.

import org.springframework.data.domain.Sort;
import org.springframework.data.domain.PageRequest;
public class UserSearchCriteria {
    UserSearchCriteria(){
        super();
        sort = "lastName";
    }
    Integer size;
    Integer page;
    String sort;
    String sortDir;

    String firstName;
    String lastName;
    Sort buildSort(){
        return new Sort(new Sort.Order(Sort.Direction.ASC, sort).ignoreCase());
    }
    PageRequest toPageRequest(){
        if(size == null){
            size = Integer.MAX_VALUE; // may or may not be a good idea for your usecase
        }
        return new PageRequest(page, size, buildSort());
    }
}

PageRequest и Sort являются частью проекта Spring Data. В моих проектах я позволил сортировку и разбиение по страницам, существующим в объекте AbstractSearchCriteria, для более легкого повторного использования, которое расширяют все мои критерии поиска, но его проще продемонстрировать, как указано выше.

В слое UserService я делегирую свой репозиторий (я также могу проверить требования к доступу, установить значения по умолчанию и т. Д. c.

import org.springframework.data.domain.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
@Transactional
public class UserService{

  @Autowired
  UserRepository userRepository;

  Page<User> findAllUsers(UserSearchCriteria userSearchCriteria){
    if(userSearchCriteria == null){
      userSearchCriteria = new UserSearchCriteria();
    }
    return userRepository.findAll(UserSearchSpecification.findByCriteria(userSearchCriteria), userSearchCriteria.toPageRequest());
  }
}

В UserSearchSpecification используется Specification API для динамического добавления поиска к вашему вызову JPA, который я считаю более чистым, чем прямое использование Criteria API.

import org.springframework.data.jpa.domain.Specification;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
public class UserSearchSpecification{

  public static Specification<User> findByCriteria(final UserSearchCriteria searchCriteria){
    return new Specification<User>() {

      @Override
      Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        List<Predicate> predicates = new ArrayList<Predicate>();

        // if firstName in criteria, do an uppercase prefix match
        if(searchCriteria.firstName != null){
          predicates.add(
            cb.like(
              cb.upper(root.get("firstName")),
              "%" + searchCriteria.lastName.toUpperCase()
            )
          );
        }

        // if lastName in criteria, do an uppercase prefix match
        if(searchCriteria.lastName != null){
          predicates.add(
            cb.like(
              cb.upper(root.get("lastName")),
              "%" + searchCriteria.lastName.toUpperCase()
            )
          );
        }
        if(predicates.size() > 0){
          return cb.and(predicates.toArray());
        }else{
          return null;
        }
      }
    }
  }
}

Это позволяет вам легко проверять переданные в параметрах остальные вызовы ( свойства UserSearchSpecification) и динамически создавать ограничения для вызова базы данных. В конце я выбрал and вместе для каждого предиката, но вы можете делать все, что захотите. Вы также можете проверить равенство вместо , больше / меньше, et, c.

Наконец, обратите внимание, что эта спецификация передается в UserRepository в методе UserService.findAllUsers. Это репозиторий Spring Data:

import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;

public interface UserRepository extends PagingAndSortingRepository<User, Long>, JpaSpecificationExecutor<User>{

}

В Spring Data вам часто нужно расширять только определенные репозитории в интерфейсе, как здесь. Spring Data может обрабатывать все остальное под капотом. Важно отметить расширение PagingAndSortingRepository, которое обрабатывает PA. аспект сортировки и сортировки, а также JpaSpecificationExecutor, который принимает Specification объекты и генерирует правильный запрос.

Это может показаться большим количеством кода, но это очень хорошо масштабируется для меня по мере роста базы кода. Как только у вас есть спецификация, вы можете легко добавить новые поля к вашему SearchCriteria объекту и добавить новые ограничения в Спецификацию, проверив новые поля и создав Predicate.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...