Как динамически обрабатывать предложение WHERE, если от клиента не было отправлено никаких входных параметров

По сути, это поток.

Клиент из REST API

GET http://localhost:8080/app-context/classroom/?studentid=1&teacherid=1&classroomno=1
  • studentid — необязательное поле
  • teacherid — необязательное поле
  • classroomno — поле опций

Этот вызов осуществляется от контроллера к сервисному уровню.

Это контроллер:

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
@RequestMapping("/app-context")
public class MyApplicationController {

    @Autowired
    private ClassRoomFetcherService classRoomFetcherService;

    @GetMapping(value = "/classroom", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> getClassRoomDetails(
        @RequestParam(value = "studentid", required = true) String studentid,
        @RequestParam(value = "teacherid", required = false) String teacherid,
        @RequestParam(value = "classroomno", required = false) String classroomno
        ) {
        try {
            List<ClassRoomData> data = classRoomFetcherService.getchDetails(studentid, teacherid, classroomno);
            return new ResponseEntity<>(data, HttpStatus.OK);
            
        } catch (Exception e) {
            log.error("operation failed", e);
            return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

}

Это услуга:

@Service
public class ClassRoomFetcherService {

    @Autowired
    private ClassRoomRepo classRoomRepo;

    public List fetchDetails(Long studentid, Long teacherid, Long classroomno){
        return return classRoomRepo.pullData(studentid, teacherid, classroomno);
    }
}

Это интерфейс репозитория:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface ClassRoomRepo extends JpaRepository<ClassRoomData, Long> {

    @Query(value = "SELECT * from class_room_data WHERE std_id= :studentid AND tchr_id = :teacherid AND cls_room_no= :classroomno" ,nativeQuery = true)
    List<ClassRoomData> pullData(@Param("studentid") Long studentid, @Param("teacherid") Long teacherid, @Param("classroomno") Long classroomno);

}

Мои варианты использования:

  1. GET http://localhost:8080/app-context/classroom/?studentid=1&teacherid=1&classroomno=1
  2. GET http://localhost:8080/app-context/classroom/?studentid=1&teacherid=1
  3. GET http://localhost:8080/app-context/classroom/?studentid=1
  4. GET http://localhost:8080/app-context/classroom/

Проблема в том, что я не могу динамически управлять предложением WHERE в одном методе, иначе в конечном итоге это приведет к написанию разных версий метода, которые специально используются в отношении входных параметров. Есть ли у вас какие-либо предложения по шаблону проектирования, который я могу использовать?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете использовать спецификацию JPA.

Определите свой репозиторий как

public interface CustomerRepository extends JpaRepository<ClassRoomData, Long>, JpaSpecificationExecutor<ClassRoomData> {}

Затем вам необходимо создать спецификацию:

        var spec = new Specification<ClassRoomData>() {
            public Predicate toPredicate(Root<ClassRoomData> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();
                if (studentId != null) {
                    predicates.add(cb.equal(root.get("stdId"), studentId));
                }
                return cb.and(predicates.toArray(Predicate[]::new));
            }
        };

Вы можете добавить обработку других параметров.

Затем вы вызываете репозиторий

List<ClassRoomData> result = customerRepository.findAll(spec);

Больше примеров вы можете найти здесь.

Спасибо @talex за исправления и помощь. но на самом деле я использую собственный запрос с несколькими таблицами с предложением JOIN, я пропустил этот запрос. обновление снова.

Dnyaneshwar Jadhav 24.08.2024 12:22

Это не проблема. API довольно гибкий. Вы можете делать все, что можете, в SQL.

talex 24.08.2024 12:49

Проблема, с которой я столкнулся, - это предложение WHERE без каких-либо входных параметров от клиента, которое заканчивается SQLGrammerException.

Dnyaneshwar Jadhav 24.08.2024 13:58

Вы должны спросить об этом. Я слышал, что есть хороший сайт для такого рода вопросов :)

talex 24.08.2024 15:03

Думаю, мне это поможет, спасибо за помощь :)

Dnyaneshwar Jadhav 25.08.2024 15:59

Другие вопросы по теме