OfferController
This commit is contained in:
parent
d7a635649a
commit
fed7cd420a
75
src/main/java/de/ph87/kleinanzeigen/crud/CrudFilter.java
Normal file
75
src/main/java/de/ph87/kleinanzeigen/crud/CrudFilter.java
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package de.ph87.kleinanzeigen.crud;
|
||||||
|
|
||||||
|
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||||
|
import jakarta.persistence.criteria.CriteriaQuery;
|
||||||
|
import jakarta.persistence.criteria.Predicate;
|
||||||
|
import jakarta.persistence.criteria.Root;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public class CrudFilter<T> {
|
||||||
|
|
||||||
|
protected final int page;
|
||||||
|
|
||||||
|
protected final int size;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
protected final List<Order> orders;
|
||||||
|
|
||||||
|
public CrudFilter(final int page, final int size, @NonNull final List<Order> orders) {
|
||||||
|
this.page = page;
|
||||||
|
this.size = size;
|
||||||
|
this.orders = orders;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public Pageable getPageable() {
|
||||||
|
return PageRequest.of(page, size, getSort());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private Sort getSort() {
|
||||||
|
return Sort.by(orders.stream().map(Order::toOrder).toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public Specification<T> getSpecification() {
|
||||||
|
return (root, query, criteriaBuilder) -> {
|
||||||
|
final List<Predicate> predicates = getPredicates(root, query, criteriaBuilder);
|
||||||
|
return criteriaBuilder.and(predicates.toArray(Predicate[]::new));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
protected List<Predicate> getPredicates(@NonNull final Root<T> root, final CriteriaQuery<?> query, @NonNull final CriteriaBuilder criteriaBuilder) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class Order {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final String property;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final Sort.Direction direction;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public Sort.Order toOrder() {
|
||||||
|
return new Sort.Order(direction, property);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
package de.ph87.kleinanzeigen.crud;
|
||||||
|
|
||||||
|
import jakarta.persistence.criteria.*;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public abstract class CrudFilterSearch<T> extends CrudFilter<T> {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
protected final String search;
|
||||||
|
|
||||||
|
protected CrudFilterSearch(final int page, final int size, @NonNull final List<Order> orders, @NonNull final String search) {
|
||||||
|
super(page, size, orders);
|
||||||
|
this.search = search;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
protected List<Predicate> getPredicates(@NonNull final Root<T> root, final CriteriaQuery<?> query, @NonNull final CriteriaBuilder criteriaBuilder) {
|
||||||
|
return new ArrayList<>(search(root, criteriaBuilder));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public List<Predicate> search(@NonNull final Root<T> root, @NonNull final CriteriaBuilder criteriaBuilder) {
|
||||||
|
final String[] words = search.replaceAll("([0-9])([a-zA-Z])", "$1 $2")
|
||||||
|
.replaceAll("([a-zA-Z])([0-9])", "$1 $2")
|
||||||
|
.replaceAll("([a-z])([A-Z])", "$1 $2")
|
||||||
|
.replaceAll("^\\W+|\\W+$", "")
|
||||||
|
.toLowerCase(Locale.ROOT)
|
||||||
|
.split("\\W+");
|
||||||
|
final List<Path<String>> fields = getFields(root);
|
||||||
|
return predicateAllWordsEachInAnyField(criteriaBuilder, words, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private List<Predicate> predicateAllWordsEachInAnyField(@NonNull final CriteriaBuilder criteriaBuilder, @NonNull final String[] words, @NonNull final List<Path<String>> fields) {
|
||||||
|
return Arrays.stream(words).map(word -> predicateWordInAnyField(criteriaBuilder, word, fields)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private Predicate predicateWordInAnyField(@NonNull final CriteriaBuilder criteriaBuilder, @NonNull final String word, @NonNull final List<Path<String>> fields) {
|
||||||
|
return fields.stream().map(field -> criteriaBuilder.like(field, "%" + word + "%")).reduce(criteriaBuilder::or).orElseThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
protected abstract List<Path<String>> getFields(@NonNull final Root<T> root);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package de.ph87.kleinanzeigen.kleinanzeigen.offer;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@CrossOrigin
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("Offer")
|
||||||
|
public class OfferController {
|
||||||
|
|
||||||
|
private final OfferService offerService;
|
||||||
|
|
||||||
|
@GetMapping("filter")
|
||||||
|
public Page<OfferDto> getAllOffers(@Nullable @RequestBody(required = false) final OfferFilter filter) {
|
||||||
|
if (filter == null) {
|
||||||
|
return offerService.filter(OfferFilter.DEFAULT());
|
||||||
|
}
|
||||||
|
return offerService.filter(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package de.ph87.kleinanzeigen.kleinanzeigen.offer;
|
||||||
|
|
||||||
|
import de.ph87.kleinanzeigen.crud.CrudFilterSearch;
|
||||||
|
import jakarta.persistence.criteria.Path;
|
||||||
|
import jakarta.persistence.criteria.Root;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class OfferFilter extends CrudFilterSearch<Offer> {
|
||||||
|
|
||||||
|
public OfferFilter(final int page, final int size, @NonNull final List<Order> orders, @NonNull final String search) {
|
||||||
|
super(page, size, orders, search);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NonNull List<Path<String>> getFields(final @NonNull Root<Offer> root) {
|
||||||
|
return List.of(root.get("title"), root.get("description"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OfferFilter DEFAULT() {
|
||||||
|
return new OfferFilter(0, 30, List.of(new Order("articleDate", Sort.Direction.DESC)), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,10 +1,11 @@
|
|||||||
package de.ph87.kleinanzeigen.kleinanzeigen.offer;
|
package de.ph87.kleinanzeigen.kleinanzeigen.offer;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
import org.springframework.data.repository.ListCrudRepository;
|
import org.springframework.data.repository.ListCrudRepository;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public interface OfferRepository extends ListCrudRepository<Offer, Long> {
|
public interface OfferRepository extends ListCrudRepository<Offer, Long>, JpaSpecificationExecutor<Offer> {
|
||||||
|
|
||||||
Optional<Offer> findByArticleId(String articleId);
|
Optional<Offer> findByArticleId(String articleId);
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import lombok.NonNull;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@ -18,19 +19,16 @@ public class OfferService {
|
|||||||
private final ApplicationEventPublisher publisher;
|
private final ApplicationEventPublisher publisher;
|
||||||
|
|
||||||
public void updateOrCreate(@NonNull final OfferCreate create, final boolean resendOnPriceChange) {
|
public void updateOrCreate(@NonNull final OfferCreate create, final boolean resendOnPriceChange) {
|
||||||
offerRepository.findByArticleId(create.getArticleId()).ifPresentOrElse(
|
offerRepository.findByArticleId(create.getArticleId()).ifPresentOrElse(existing -> {
|
||||||
existing -> {
|
|
||||||
if (existing.update(create, resendOnPriceChange)) {
|
if (existing.update(create, resendOnPriceChange)) {
|
||||||
final OfferDto dto = toDto(existing);
|
final OfferDto dto = toDto(existing);
|
||||||
publisher.publishEvent(dto);
|
publisher.publishEvent(dto);
|
||||||
}
|
}
|
||||||
},
|
}, () -> {
|
||||||
() -> {
|
|
||||||
final Offer offer = offerRepository.save(new Offer(create, resendOnPriceChange));
|
final Offer offer = offerRepository.save(new Offer(create, resendOnPriceChange));
|
||||||
final OfferDto dto = toDto(offer);
|
final OfferDto dto = toDto(offer);
|
||||||
publisher.publishEvent(dto);
|
publisher.publishEvent(dto);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public OfferDto toDto(final Offer offer) {
|
public OfferDto toDto(final Offer offer) {
|
||||||
@ -41,4 +39,9 @@ public class OfferService {
|
|||||||
return offerRepository.findById(offerDto.getId()).orElseThrow();
|
return offerRepository.findById(offerDto.getId()).orElseThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public Page<OfferDto> filter(@NonNull final OfferFilter filter) {
|
||||||
|
return offerRepository.findAll(filter.getSpecification(), filter.getPageable()).map(OfferDto::new);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user