Chcę utworzyć usługę w celu wypełnienia listy rozwijanej z bazy danych. Próbowałem tego:

Klasa kupca:

export class Merchant {
  constructor(
    public id: string,
    public name: string,
    public state_raw: string,
    public users: string,
  ) {}
}

Obsługa sprzedawcy:

 getList(): Observable<Merchant> {
    return this.http.get<Merchant>(environment.api.urls.merchants.base, {});
  }

Zapytanie SQL:

@Override
    public Iterable<Merchants> findAll() {
        String hql = "select e from " + Merchants.class.getName() + " e";
        TypedQuery<Merchants> query = entityManager.createQuery(hql, Merchants.class);
        List<Merchants> merchants = query.getResultList();
        return merchants;
    }

Przykład pracy:

    @GetMapping("/list")
public Iterable<Merchants> getMerchantsList() {
    return merchantRepository
            .findAll();
}

Próbowałem tego:

@GetMapping("/list")
public ResponseEntity<?> getMerchantsList() {
    return StreamSupport.stream(merchantRepository.findAll().spliterator(), false)
            .map(mapper::toDTO)
            .map(ResponseEntity::ok)
            .findFirst()
            .orElseGet(() -> notFound().build());
}

Chcę użyć mapera przed wysłaniem odpowiedzi. Obecnie lista w Angularze jest pusta. Prawdopodobnie powinienem zwrócić Iterable<Merchants>, a nie ResponseEntity<MerchantDTO>?

Używam Javy 10.

0
Peter Penzov 3 listopad 2018, 12:41

1 odpowiedź

Najlepsza odpowiedź

Po obu stronach jest kilka problemów. Zacznijmy od strony serwera. Chcesz zwrócić listę sprzedawców, aby wypełnić listę rozwijaną listę, więc poprawnie nazwałeś metodę getMerchantsList(). Ale zamiast zwracać listę, jak wskazuje jej nazwa, zwraca void. void to nic, nada, stąd pusta odpowiedź.

Musisz więc zwrócić List<Merchant> lub, jeśli naprawdę chcesz (ale nie jest to tutaj konieczne, ponieważ nie chcesz ustawiać niczego poza treścią odpowiedzi), ResponseEntity<List<Merchant>>. Dzwonienie findFirst() przynosi efekt przeciwny do zamierzonego. Nie chcesz pierwszego kupca na liście. Chcesz całą listę:

@GetMapping("/list")
public List<MerchantDTO> getMerchantsList() {
    return StreamSupport.stream(merchantRepository.findAll().spliterator(), false)
            .map(mapper::toDTO)
            .collect(Collectors.toList());
}

Lub

@GetMapping("/list")
public ResponseEntity<List<MerchantDTO>> getMerchantsList() {
    List<MerchantDTO> list = StreamSupport.stream(merchantRepository.findAll().spliterator(), false)
            .map(mapper::toDTO)
            .collect(Collectors.toList());
    return ResponseEntity.ok(list);
}

Zauważ, że kod byłby prostszy, gdyby metoda findAll() zwróciła List zamiast Iterable. Możesz po prostu użyć findAll().stream(), aby uzyskać strumień.

Po stronie klienta popełniasz ten sam błąd. Chcesz, aby treść odpowiedzi była tablicą sprzedawców, aby wypełnić listę rozwijaną. Ale używasz Observable<Merchant>. Potrzebujesz Observable<Array<Merchant>>. A przekazywanie pustego obiektu opcji do get() jest bezużyteczne:

getList(): Observable<Array<Merchant>> {
  return this.http.get<Array<Merchant>>(environment.api.urls.merchants.base);
}

Wreszcie okłamujesz się, tworząc klasę. HttpClient nigdy nie utworzy instancji Twojej klasy. Nie wie o tym i po prostu przetworzył otrzymany JSON na zwykłe stare obiekty JavaScript. Więc naprawdę powinieneś zdefiniować interfejs, a nie klasę:

export interface Merchant {
  id: string;
  name: string;
  state_raw: string;
  users: string;
}

Naprawdę powinieneś też używać Spring-data-jpa. Znacznie uprościłoby to twoje repozytoria.

2
JB Nizet 3 listopad 2018, 13:03