> Java > java지도 시간 > 본문

Java 도구 클래스를 사용하여 보고서를 효율적으로 작성하는 방법

WBOY
풀어 주다: 2023-04-14 19:16:10
앞으로
1125명이 탐색했습니다.

Java 코드를 사용하여 보고서를 작성하는 이유

보고서 데이터의 경우 대부분의 경우 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;
로그인 후 복사

AggregationData는 데이터 행을 나타내며, aggregationMap의 키는 테이블 이름, 값은 해당 data

이 인터페이스를 자세히 살펴보겠습니다

//  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);
}
로그인 후 복사

은 컬렉션 contractDetails를 테이블 이름 t1,

 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())
                )
로그인 후 복사

이 구현은 확실히 더 간단하고, 오류 가능성을 줄이고, 코드 양을 줄이고, 효율성을 향상시킵니다.

장점

컬렉션 간의 연결 작업을 구현하며, 한 번에 여러 컬렉션을 지속적으로 연결할 수 있는 스트리밍 작업입니다.

은 Stream과의 변환을 실현합니다. 필터링, 변환, 그룹화 등 스트림의 기능을 사용하여 다양하고 복잡한 작업을 구현할 수 있습니다.

  • 어느 정도 효율성은 보장됩니다. 맵 최적화는 동등한 연결에 사용되며, 내부 연결이 이루어지면 최적화를 위해 작은 테이블을 사용하여 큰 테이블에 연결하는 경우도 있습니다. 그리고 Bean은 행으로 변환되어 데이터를 집계할 때 cglib에서 BeanMap을 사용하여 메모리 사용량과 성능 소비를 줄입니다

위 내용은 Java 도구 클래스를 사용하여 보고서를 효율적으로 작성하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:yisu.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿