Heim  >  Artikel  >  Java  >  So verwenden Sie Java-Toolklassen zum effizienten Schreiben von Berichten

So verwenden Sie Java-Toolklassen zum effizienten Schreiben von Berichten

WBOY
WBOYnach vorne
2023-04-14 19:16:101101Durchsuche

Warum Java-Code zum Schreiben von Berichten verwenden?

Für Berichtsdaten wird in den meisten Fällen das Schreiben von SQL verwendet, um Datenquellen für große Bildschirme/Berichte bereitzustellen. In einigen komplexen Situationen kann jedoch die alleinige Verwendung von SQL nicht implementiert werden, oder wenn dies der Fall ist ist schwer zu implementieren. Es wird komplexe Logik durch Code implementieren und schließlich das Ergebnis zurückgeben.

Aufgetretene Probleme

Bei relativ komplexen Berichten ist es häufig erforderlich, Daten zu verbinden, dh Operationen zwischen Tabellen zusammenzuführen, zu gruppieren und zu berechnen. SQL unterstützt diese Operationen natürlich und ist einfach zu implementieren. Aber wenn wir Daten in Java-Code verbinden müssen, ist die native Unterstützung nicht so benutzerfreundlich. Wir implementieren es oft so Filtern Sie die Daten mit dem Status = „Signiert“ heraus.

Gruppieren Sie sie dann entsprechend der Vertragsnummer in den Vertragsdetails und ermitteln Sie die Geldsumme, die jeweils der Vertragsnummer entspricht.

Die endgültige Ausgabe sollte eine Karte sein Diese Implementierung

List<ContractDetail> contractDetails; // 合同明细集合,合同会重复
List<ContractInfo> contractInfos; // 合同主要信息,不会有重复合同

Offensichtlich ist diese Implementierung komplizierter, da die Verwendung von SQL nichts weiter ist als das Beitreten und Hinzufügen von Gruppen nach. Summe. Dieses Problem lässt sich leicht lösen. Dann werfen Sie einen Blick auf die folgende Tool-Klasse und überlegen Sie, ob es eine einfachere Möglichkeit gibt, sie umzusetzen.

Tool-Klasse

CollectionDataStream

Die Funktion des Sammlungsdatenstroms CollectionDataStream besteht darin, Sammlungen über Schnittstellen zuzuordnen, zwei Operationen ähnlich dem SQL-Join und Left-Join zu implementieren

und die Funktion der gegenseitigen Konvertierung mit Stream in Java zu realisieren.

Die Aggregationsdatenstruktur wandelt die Sammlung in eine Datenstruktur ähnlich einer Tabellenstruktur um, einschließlich Tabellenname und Daten.

public class ContractDetail {
    /**
     * 合同编号
     */
    private String contractNo;
    /**
     * 总金额
     */
    private BigDecimal moneyTotal;
}
public class ContractInfo {
    /**
     * 合同编号
     */
    private String contractNo;
    /**
     * 状态
     */
    private String status;
}

AggregationData stellt eine Datenzeile dar, der Schlüssel von aggregationMap ist der Tabellenname und der entsprechende Wert data

Werfen wir einen Blick auf diese Schnittstelle im Detail

Map<String /* 合同编码 */, BigDecimal /* 对应moneyTotal之和 */> result;

Achten Sie auf den Unterschied zwischen joinUseHashOnEqualCondition und Join-Methoden.

Wenn es sich bei der Verbindung zwischen Sätzen um eine Feldgleichwertverbindung handelt, verwenden Sie „joinUseHashOnEqualCondition“, die intern die Kartengruppierung zum Verbinden verwendet. Wenn Sie Join direkt verwenden, können die Verbindungsbedingungen angepasst werden, die Bedingung wird jedoch durch Doppelschleifen beurteilt, was weniger effizient ist. Daher ist es bei gleichen Werten effizienter, joinUseHashOnEqualCondition zu verwenden.

So verwenden Sie

Oder nehmen Sie die oben genannten Anforderungen als Beispiel.

Verbinden Sie zunächst die beiden Sammlungen ContractInfos und geben Sie ContractInfos einen Alias ​​t2. Die Verbindungsbedingung ist die äquivalente Verbindung von ContractNo von t1 und ContractNol von ContractInfos. Nach der Verbindung wird ein neuer aggregierter Datenstrom erhalten

Natürlich können Sie zur Implementierung auch eine benutzerdefinierte Verbindung verwenden

//  setp 1 过滤出 已签订状态的合同编码
Set<String> stopContract = contractInfos.stream()
                .filter(it -> "已签订".equals(it.getStatus()))
                .map(ContractInfo::getContractNo).collect(Collectors.toSet());
//step2 根据 step1的合同编码集合过滤出状态正确的contractDetail
  contractDetails = contractDetails.stream()
                .filter(it -> stopContract.contains(it.getContractNo()))
                .collect(Collectors.toList());
//step3 根据contractNo分别累加对应的moneyTotal
 Map<String, BigDecimal> result = new HashMap<>();
 contractDetails.stream().forEach(it -> {
            BigDecimal moneyTotal = Optional.ofNullable(result.get(it.getContractNo()))
                    .orElse(BigDecimal.ZERO);
            moneyTotal = moneyTotal.add(it.getMoneyTotal() != null ? it.getMoneyTotal() : BigDecimal.ZERO);
            result.put(it.getContractNo(), moneyTotal);
        });

Hier durch innere Verbindung, Dann spielt es auch eine filternde Rolle. Nachdem die Verbindung hergestellt wurde, müssen wir für die Berechnung noch eine Gruppierung durchführen, also müssen wir die nächste Toolklasse verwenden.

MyCollectors

ist eine Erweiterung der nativen Collectors in Stram, die häufigere Gruppierungsvorgänge für Berichte implementiert,

public class AggregationData {
    Map<String, Map> aggregationMap;
    private AggregationData(){
        aggregationMap = new HashMap<>();
    }
    //key 为别名,value为对应对象
    public AggregationData(String tableName, Object data) {
        aggregationMap = new HashMap<>();
        aggregationMap.put(tableName, BeanUtil.beanToMap(data));
    }
    public Map<String, Map> getRowAllData() {
        return aggregationMap;
    }
    public Map getTableData(String tableName) {
        if (!aggregationMap.containsKey(tableName)) {
            throw new DataStreamException(tableName + ".not.exists");
        }
        return aggregationMap.get(tableName);
    }
    public void setTableData(String tableName, Object data) {
        if(aggregationMap.containsKey(tableName)){
            throw new DataStreamException(tableName+".has.been.exists!");
        }
        aggregationMap.put(tableName, BeanUtil.beanToMap(data));
    }
    private void setTableData(String tableName, Map<String, Object> data) {
        Map<String, Object> tableData =
                Optional.ofNullable(aggregationMap.get(tableName)).orElse(new HashMap<String, Object>());
        tableData.putAll(data);
        aggregationMap.put(tableName, tableData);
    }
    public AggregationData copyAggregationData() {
        AggregationData aggregationData = new AggregationData();
        for (String tableName : this.getRowAllData().keySet()) {
            aggregationData.setTableData(tableName, this.getRowAllData().get(tableName));
        }
        return aggregationData;
    }
}

Kombination Die verwendete Implementierung

import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
public interface CollectionDataStream<T> {
    /**
     *将集合转化为数据流,并给一个别名
     * @param tableName
     * @param collection
     * @return
     */
    static CollectionDataStream<AggregationData> of(String tableName, Collection<?> collection) {
        return new CollectionDataStreamImpl(tableName, collection);
    }
    /**
     *将 Stream转化为数据流,并给一个别名
     * @param tableName
     * @param collection
     * @return
     */
    static CollectionDataStream<AggregationData> of(String tableName, Stream<?> collection) {
        return new CollectionDataStreamImpl(tableName, collection);
    }
    /**
     * 内连接,可自定义连接条件,使用双循环
     *
     * @param tableName
     * @param collection
     * @param predict
     * @param <T1>
     * @return
     */
    <T1> CollectionDataStream<T> join(String tableName, Collection<T1> collection, JoinPredicate<T, T1> predict);
    /**
     * 等值内连接,使用map优化
     *
     * @param collection
     * @param tableName
     * @param aggregationMapper
     * @param dataValueMapper
     * @param <T1>
     * @param <R>
     * @return
     */
    //等值条件推荐用法
    <T1, R> CollectionDataStream<T> joinUseHashOnEqualCondition(String tableName, Collection<T1> collection, Function<T, R> aggregationMapper, Function<T1, R> dataValueMapper);
    /**
     * 左连接,可自定义连接条件,使用双循环
     *
     * @param tableName
     * @param collection
     * @param predict
     * @param <T1>
     * @return
     */
    <T1> CollectionDataStream<T> leftJoin(String tableName, Collection<T1> collection, JoinPredicate<T, T1> predict);
    /**
     * 等值左连接,使用map优化
     *
     * @param collection
     * @param tableName
     * @param aggregationMapper
     * @param dataValueMapper
     * @param <T1>
     * @param <R>
     * @return
     */
    <T1, R> CollectionDataStream<T> leftJoinUseHashOnEqualCondition( String tableName, Collection<T1> collection,Function<T, R> aggregationMapper, Function<T1, R> dataValueMapper);
    Stream<T> toStream();
    Stream<Map> toStream(String tableName);
    <R> Stream<R> toStream(String tableName, Class<R> clzz);
    <R> Stream<R> toStream(Function<AggregationData, R> mapper);
}

Diese Implementierung ist offensichtlich einfacher, verringert die Fehlerwahrscheinlichkeit, reduziert die Codemenge und verbessert die Effizienz.

Vorteile

realisiert den Verbindungsvorgang zwischen Sammlungen und ist ein Streaming-Vorgang, der mehrere Sammlungen kontinuierlich auf einmal verbinden kann.

realisiert die Konvertierung zu und von Stream. Mithilfe der Stream-Funktionen können verschiedene komplexe Vorgänge implementiert werden, z. B. Filtern, Konvertieren, Gruppieren usw.

Die Effizienz wird bis zu einem gewissen Grad für äquivalente Verknüpfungen verwendet, und wenn innere Verknüpfungen erstellt werden, werden zur Optimierung kleine Tabellen verwendet, um eine Verbindung zu großen Tabellen herzustellen. und Beans werden in Zeilen konvertiert. Verwenden Sie BeanMap unter cglib, um den Speicherverbrauch und den Leistungsverbrauch zu reduzieren

Das obige ist der detaillierte Inhalt vonSo verwenden Sie Java-Toolklassen zum effizienten Schreiben von Berichten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen