Siirry pääsisältöön

Mukautetut tietolähteet 25.02

Avaa ChatGPT:ssä

Kun tietosi sijaitsevat sovelluksesi ulkopuolella - REST-API:ssa, tietokannassa tai ulkoisessa palvelussa - sinun täytyy luoda mukautettu varaston toteutus. Luokka DelegatingRepository tekee tämän yksinkertaiseksi antamalla sinun tarjota funktioita sen sijaan, että toteuttaisit koko luokan.

Kuinka DelegatingRepository toimii

DelegatingRepository on konkreettinen luokka, joka laajentaa AbstractQueryableRepository -luokkaa. Sen sijaan, että toteuttaisit abstrakteja metodeja, tarjoat kolme funktiota konstruktorissa:

DelegatingRepository<User, UserFilter> repository = new DelegatingRepository<>(
// 1. Etsintäfunktio - palauttaa suodatetut/järjestetyt/sivutetut tiedot
criteria -> userService.findUsers(criteria),

// 2. Laskentafunktio - palauttaa suodattimen kokonaismäärän
criteria -> userService.countUsers(criteria),

// 3. Etsi avaimen avulla - palauttaa yksittäisen entiteetin ID:n perusteella
userId -> userService.findById(userId)
);

Jokaisella funktiolla on oma erityinen tarkoitus:

Etsintäfunktio vastaanottaa RepositoryCriteria -objektin, joka sisältää:

  • getFilter() - mukautettu suodatinobjektisi (tyyppi F)
  • getOffset() ja getLimit() - sivutusta varten
  • getOrderCriteria() - luettelo järjestyssäännöistä

Tämän funktion on palautettava Stream<T> entiteettejä, jotka vastaavat kriteerejä. Virta voi olla tyhjää, jos yhtään mätsäävää löydöstä ei ole.

Laskentafunktio vastaanottaa myös kriteerit, mutta käyttää tyypillisesti vain suodatinosaa. Se palauttaa vastaavien entiteettien kokonaismäärän, ottaen huomioon vain suodatuksen. Tätä käytetään käyttöliittymäkomponenteissa näyttämään kokonaisvarastot tai laskemaan sivuja.

Etsi avaimen avulla vastaanottaa entiteettiavaimen (yleensä ID) ja palauttaa Optional<T>. Palauta Optional.empty(), jos entiteettiä ei ole olemassa.

REST API -esimerkki

REST API:n kanssa integroiminen edellyttää, että muutat varaston kriteerit HTTP-pyyntöparametreiksi. Aloita määrittämällä suodatinluokka, joka vastaa API:si kyselymahdollisuuksia:

public class UserFilter {
private String department;
private String status;
// gettereitä ja settereitä...
}

Tämä suodatinluokka edustaa hakuparametrejä, joita API:si hyväksyy. Varasto välittää tämän luokan instanssit funktioihisi suodatuksen soveltamisen yhteydessä.

Luo varasto funktioilla, jotka kääntävät kriteerit API-kutsuiksi:

DelegatingRepository<User, UserFilter> apiRepository = new DelegatingRepository<>(
// Etsi käyttäjiä
criteria -> {
Map<String, String> params = buildParams(criteria);
List<User> users = restClient.get("/users", params);
return users.stream();
},

// Laske käyttäjät
criteria -> {
Map<String, String> filterParams = buildFilterParams(criteria.getFilter());
return restClient.getCount("/users/count", filterParams);
},

// Etsi ID:n mukaan
userId -> restClient.getById("/users/" + userId)
);

buildParams()-menetelmä ekstraktiarvoittaa kriteereistä ja muuntaa ne kyselyparametreiksi kuten ?department=Sales&status=active&offset=20&limit=10. REST-asiakkaasi suorittaa sitten varsinaisen HTTP-pyynnön ja deserialisoi vastauksen.

Tietokantaesimerkki

Tietokanta-integrointi seuraa samankaltaista kaavaa, mutta muuntaa kriteerit SQL-kyselyiksi. Avainero on SQL-generaation ja parametrien sitomisen käsittely:

DelegatingRepository<Customer, CustomerFilter> dbRepository = new DelegatingRepository<>(
// Kysely suodattimella, järjestäminen, sivutus
criteria -> {
String sql = buildQuery(criteria);
return jdbcTemplate.queryForStream(sql, rowMapper);
},

// Laske vastaavat tietueet
criteria -> {
String countSql = buildCountQuery(criteria.getFilter());
return jdbcTemplate.queryForObject(countSql, Integer.class);
},

// Etsi pääavaimen mukaan
customerId -> {
String sql = "SELECT * FROM customers WHERE id = ?";
return jdbcTemplate.queryForObject(sql, rowMapper, customerId);
}
);

buildQuery()-menetelmä rakentaisi SQL:ää, kuten:

SELECT * FROM customers
WHERE status = ? AND region = ?
ORDER BY created_date DESC, name ASC
LIMIT ? OFFSET ?

Suodatinobjektin ominaisuudet vastaavat WHERE-lauseen ehtoja, kun taas sivutus ja lajittelu käsitellään LIMIT/OFFSET- ja ORDER BY -lauseilla.

Käyttö käyttöliittymäkomponenttien kanssa

Varastomallin kauneus on siinä, että käyttöliittymäkomponentit eivät tiedä tai välitä, mistä data tulee. Onko se muistissa oleva kokoelma, REST-API vai tietokanta, käyttö on identtistä:

// Luo ja määrittele varasto
Repository<User> repository = createApiRepository();
UserFilter filter = new UserFilter();
filter.setDepartment("Engineering");
repository.setBaseFilter(filter);

// Kiinnitä taulukkoon
Table<User> table = new Table<>();
table.setRepository(repository);

// Taulukko näyttää automaattisesti suodatetut insinöörikäyttäjät

Kun käyttäjät vuorovaikuttavat Table (lajittelevat sarakkeita, vaihtavat sivuja), Table kutsuu varastosi funktioita päivitettyjen kriteerien kanssa. Funktiot kääntävät nämä API-kutsuiksi tai SQL-kyselyiksi, ja taulukko päivittyy automaattisesti tulosten kanssa.

Milloin laajentaa AbstractQueryableRepository

Jos tarvitset mukautettuja metodeja tai monimutkaista alustamista, laajenna AbstractQueryableRepository suoraan:

public class CustomUserRepository extends AbstractQueryableRepository<User, UserFilter> {
@Override
public Stream<User> findBy(RepositoryCriteria<User, UserFilter> criteria) {
// Toteutus
}

@Override
public int size(RepositoryCriteria<User, UserFilter> criteria) {
// Toteutus
}

@Override
public Optional<User> find(Object key) {
// Toteutus
}

// Lisää mukautettuja metodeja
public List<User> findActiveManagers() {
// Mukautettu kyselylogiikka
}
}