보고서 데이터의 경우 대부분의 경우 SQL 작성을 사용하여 대형 화면/보고서에 대한 데이터 소스를 제공합니다. 그러나 일부 복잡한 상황에서는 SQL만으로는 구현할 수 없거나, 구현하기 어렵기 때문에 코드를 통해 복잡한 로직을 구현하고 최종적으로 결과를 반환합니다.
비교적 복잡한 보고서의 경우 데이터 연결, 즉 테이블 간 조인, 그룹화, 연산 연산이 필요한 경우가 많습니다. SQL은 자연스럽게 이러한 작업을 지원하며 구현이 쉽습니다. 하지만 자바 코드에서 데이터를 연결해야 할 때 기본 지원은 그렇게 친숙하지 않습니다. , 상태 = '서명됨'으로 데이터를 필터링합니다.
그런 다음 contractDetails의 contractNo에 따라 그룹화하고 각각 각 contractNo에 해당하는 금액 합계를 찾습니다.
최종 출력은 맵이어야 합니다
List<ContractDetail> contractDetails; // 合同明细集合,合同会重复 List<ContractInfo> contractInfos; // 合同主要信息,不会有重复合同
일반적으로 우리는 할 것입니다 이 구현
public class ContractDetail { /** * 合同编号 */ private String contractNo; /** * 总金额 */ private BigDecimal moneyTotal; } public class ContractInfo { /** * 合同编号 */ private String contractNo; /** * 状态 */ private String status; }
분명히 이 구현은 더 복잡합니다. 왜냐하면 SQL을 사용하는 것은 그룹별 조인 및 추가에 지나지 않기 때문입니다. 합집합. 이 문제는 쉽게 해결될 수 있습니다. 그런 다음 다음 도구 클래스를 살펴보고 이를 구현하는 더 간단한 방법이 있는지 생각해 보세요.
Tool 클래스
CollectionDataStream
컬렉션 데이터 스트림 CollectionDataStream의 기능은 인터페이스를 통해 컬렉션을 연결하고, SQL Join 및 Left Join
과 유사한 두 가지 작업을 구현하고, Java에서 Stream과의 상호 변환 기능을 구현하는 것입니다.
Map<String /* 合同编码 */, BigDecimal /* 对应moneyTotal之和 */> result;
이 인터페이스를 자세히 살펴보겠습니다
// 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); });
joinUseHashOnEqualCondition과 조인 방법의 차이점에 주목하세요.
세트 간 연결이 필드 동일 값 연결인 경우 내부적으로 맵 그룹화를 사용하여 조인하는 JoinUseHashOnEqualCondition을 사용하세요. Join을 직접 사용하면 연결 조건을 맞춤화할 수 있지만 이중 루프를 통해 조건을 판단하므로 효율성이 떨어집니다. 따라서 동일한 값의 경우에는 JoinUseHashOnEqualCondition을 사용하는 것이 더 효율적입니다.
사용 방법
또는 위의 요구 사항을 예로 들어
먼저 두 컬렉션을 연결합니다.
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; } }
코드 분석
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); }
CollectionDataStream.of("t1", contractDetails) .joinUseHashOnEqualCondition( contractInfos.stream().filter(it -> "已签订".equals(it.getStatus())).collect(Collectors.toList()), "t2", agg -> agg.getTableData("t1").get("contractNo"), ContractInfo::getContractNo );
을 사용하여 데이터 스트림으로 변환하는 것입니다. contractInfos에 별칭 t2를 제공합니다. 연결 조건은 t1의 contractNo 및 contractInfos의 contractNol과 동일한 연결입니다. 연결 후 새로운 집계 데이터 스트림을 얻습니다
물론 사용자 정의 연결을 사용하여 구현할 수도 있습니다.
CollectionDataStream.of("t1", contractDetails)
여기서 내부 연결을 통해, 그리고 필터링 역할도 합니다. 연결이 완료된 후에도 계산을 위해 그룹화해야 하므로 다음 도구 클래스를 사용해야 합니다.
MyCollectors
는 보고서에 대해 보다 일반적인 그룹화 작업을 구현하는 stram의 기본 수집기 확장인
.joinUseHashOnEqualCondition( contractInfos.stream().filter( "t2", it -> "已签订".equals(it.getStatus())).collect(Collectors.toList()), agg -> agg.getTableData("t1").get("contractNo"), ContractInfo::getContractNo );
입니다. 조합 사용된 구현
CollectionDataStream.of("t1", contractDetails) .join("t2", contractInfos.stream().filter(it -> "已签订".equals(it.getStatus())).collect(Collectors.toList()), (agg, data) -> agg.getTableData("t1").get("contractNo").equals(data.getContractNo()) )
이 구현은 확실히 더 간단하고, 오류 가능성을 줄이고, 코드 양을 줄이고, 효율성을 향상시킵니다.
어느 정도 효율성은 보장됩니다. 맵 최적화는 동등한 연결에 사용되며, 내부 연결이 이루어지면 최적화를 위해 작은 테이블을 사용하여 큰 테이블에 연결하는 경우도 있습니다. 그리고 Bean은 행으로 변환되어 데이터를 집계할 때 cglib에서 BeanMap을 사용하여 메모리 사용량과 성능 소비를 줄입니다
위 내용은 Java 도구 클래스를 사용하여 보고서를 효율적으로 작성하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!