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.
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; }
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.
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.
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!