Фильтрация по списку значений и фильтру на основе JpaSpecificationExecutor

207
12 декабря 2021, 14:50

Все это происходит в проекте на базе Spring Boot 2, DB - PostgreSQL.

Есть лист идентификаторов вложенных сущностей(устройств) и фильтр на основе спецификации, нужно принять в GET лист этих идентификаторов и фильтр, собственно, отфильтровать таблицу в базе на основе этих параметров и выдать список записей по этим параметрам.

Пример сущности:

@Entity
@Table
public class DeviceEvent{
@ManyToOne
private User admin;
@ManyToOne
private Device device;
@Column
private TaskObject.Type type;
@Column
private Integer result;
@Column
private Date added;
@Column
private Date updated;
@Column(name = "icursor")
private Long cursor;
@ManyToOne
private City city;
@ManyToOne
private District district;
@Column
private String text;
}

Пример спецификации:

public class DeviceEventsSpec {
    public static Specification<Query> find(DeviceEventsFilter deviceEventsFilter) {
        return (root, query, cb) -> {
            final Collection<Predicate> predicates = new ArrayList<>();
            if (deviceEventsFilter.getType() != null) {
                predicates.add(cb.equal(root.get("type"), deviceEventsFilter.getType()));
            }
            if (deviceEventsFilter.getCompany() != null){
                predicates.add(cb.equal(root.get("company"), deviceEventsFilter.getCompany()));
            }
            if (deviceEventsFilter.getCity() != null){
                predicates.add(cb.equal(root.get("city"), deviceEventsFilter.getCity()));
            }
            if (deviceEventsFilter.getDistrict() != null){
                predicates.add(cb.equal(root.get("district"), deviceEventsFilter.getDistrict()));
            }
            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        };
    }
}

Пример контроллера:

    @RestController("devicesEvents")
    @RequestMapping("/devices/events")
    public class Events extends Base {
        @Autowired
        DeviceEventsRepo queryRepo;

        @ApiOperation(value = "Поиск событий по фильтрам", response = Query.class)
        @GetMapping("find")
        public Page<Query> find(List<Long> devices, Pageable pageable, DeviceEventsFilter de
viceEventsFilter) {
        if(getUser().getRole() != User.Role.ADMIN) {
            deviceEventsFilter.setCompany(getUser().getCompany());
            if(getUser().getCity() != null) {
                deviceEventsFilter.setCity(getUser().getCity());
            }
            if(getUser().getDistrict() != null) {
                deviceEventsFilter.setDistrict(getUser().getDistrict());
            }
        }
        return queryRepo.findAll(DeviceEventsSpec.find(deviceEventsFilter), pageable);
    }
}
Answer 1

в конце концов помогла такая штука, как комбинирование предикатов.

https://www.baeldung.com/jpa-and-or-criteria-predicates

Изменить немного кода в спецификации и готово)

public class DeviceEventsSpec {
public static Specification<Query> find(DeviceEventsFilter deviceEventsFilter, List<Device> devices) {
    return (root, query, cb) -> {
        Collection<Predicate> finalPredicates = new ArrayList<>();
        final Collection<Predicate> predicates = new ArrayList<>();
        if (deviceEventsFilter.getType() != null) {
            predicates.add(cb.equal(root.get("type"), deviceEventsFilter.getType()));
        }
        if (deviceEventsFilter.getCompany() != null){
            predicates.add(cb.equal(root.get("company"), deviceEventsFilter.getCompany()));
        }
        if (deviceEventsFilter.getCity() != null){
            predicates.add(cb.equal(root.get("city"), deviceEventsFilter.getCity()));
        }
        if (deviceEventsFilter.getDistrict() != null){
            predicates.add(cb.equal(root.get("district"), deviceEventsFilter.getDistrict()));
        }
        if (deviceEventsFilter.getAdded() != null){
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(deviceEventsFilter.getAdded());
            calendar.set(Calendar.HOUR, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);

            Calendar calendarEnd = (Calendar) calendar.clone();
            calendarEnd.setTime(deviceEventsFilter.getAdded());
            calendarEnd.set(Calendar.HOUR, 23);
            calendarEnd.set(Calendar.MINUTE, 59);
            calendarEnd.set(Calendar.SECOND, 59);
            predicates.add(cb.greaterThanOrEqualTo(root.get("added"), calendar.getTime()));
            predicates.add(cb.lessThanOrEqualTo(root.get("added"), calendarEnd.getTime()));
        }
        Predicate predicate = cb.and(predicates.toArray(new Predicate[predicates.size()]));
        if (devices != null){
            if (devices.size() != 0) {
                for (Device device : devices) {
                    deviceEventsFilter.setDevice(device);
                    Predicate predicate1 = cb.equal(root.get("device"), deviceEventsFilter.getDevice());
                    finalPredicates.add(cb.and(predicate, predicate1));
                }
                return cb.or(finalPredicates.toArray(new Predicate[finalPredicates.size()]));
            }
        } else if (deviceEventsFilter.getDevice() != null){
            predicates.add(cb.equal(root.get("device"), deviceEventsFilter.getDevice()));
        }

        return cb.and(predicates.toArray(new Predicate[predicates.size()]));
    };
}

}

READ ALSO
Шифрование Triple DES

Шифрование Triple DES

Есть ключ зашифрованный Triple DES на C# 16 байтНеобходимо расшифровать в коде написанном на Java, но Triple DES на java из документации следует:

241
Будильники на Spring

Будильники на Spring

У меня есть объекты рассылки, в которых есть параметр времениВ это время они должны быть отправлены на e-mail пользователям

145
Maven не видит класс из другого модуля

Maven не видит класс из другого модуля

При сборке проекта Maven выдает следующие ошибки:

246
Patch сущности в REST Spring MVC

Patch сущности в REST Spring MVC

изучаю принципы REST, остановился на обновлении сущностиНе могу понять, как в сущность передать поля, которые передаю в запросе и затем обновить...

183