最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java使用FastExcel實(shí)現(xiàn)合并單元格

 更新時間:2024年12月17日 08:21:40   作者:VipSoft  
FastExcel 是一個采用純 java 開發(fā)的 excel 文件讀寫組件,支持 Excel'97(-2003)(BIFF8)文件格式,本文主要介紹了如何使用FastExcel實(shí)現(xiàn)合并單元格,需要的可以參考下

使用FastExcel數(shù)據(jù)導(dǎo)出:官網(wǎng): https://idev.cn/fastexcel/zh-CN

需求

信用代碼、填報人,唯一時,將:信用代碼、單位名稱、填報人,進(jìn)行 row 合并,并垂直居中對齊

思路

這邊不需要做列合并,所以采用了 RowWriteHandler
思路,

  • 指定唯一值,根據(jù)某個或多個單元格確定相當(dāng)?shù)臄?shù)據(jù)行(代碼中的 ExcelCellMergeStrategy. uniqueCol)
  • 判斷當(dāng)前行的唯一列的數(shù)據(jù)和上一行是否相等,如果相等繼續(xù),要合并的行數(shù) mergeCount + 1
  • 如果當(dāng)前行和上一行不相等,說明前面的數(shù)據(jù)需要做合并處理了。同時將當(dāng)前行做為下一次待合并的起始行

實(shí)現(xiàn)

Excel導(dǎo)出單元格全量合并策略

package com.vipsoft.handler;


import cn.idev.excel.write.handler.RowWriteHandler;
import cn.idev.excel.write.metadata.holder.WriteSheetHolder;
import cn.idev.excel.write.metadata.holder.WriteTableHolder;

import org.apache.poi.ss.usermodel.*;

import org.apache.poi.ss.util.CellRangeAddress;

import java.util.ArrayList;
import java.util.List;

/**
 * Excel導(dǎo)出單元格全量合并策略
 */
public class ExcelCellMergeStrategy implements RowWriteHandler {

    private int mergeRowIndex;//從哪一行開始合并
    private List<Integer> mergeColumnIndex = new ArrayList<>();//excel合并的列
    private int[] uniqueCol;//合并的唯一標(biāo)識,根據(jù)指定的列,確定數(shù)據(jù)是否相同
    private int totalRow;//總行數(shù)

    private int lastRow;
    private int firstCol;
    private int lastCol;
    private int firstRow;

    private int mergeCount = 1;

    /**
     * @param mergeRowIndex
     * @param mergeColIndex 支持范圍如:0-3,6,9
     * @param uniqueCol     唯一標(biāo)識,1列或多列 數(shù)據(jù)組成唯一值
     * @param totalRow      總行數(shù)(從0開始):List.size -1  + 跳過的表頭
     */
    public ExcelCellMergeStrategy(int mergeRowIndex, Object[] mergeColIndex, int[] uniqueCol, int totalRow) {
        this.mergeRowIndex = mergeRowIndex;
        for (Object item : mergeColIndex) {
            if (item.toString().contains("-")) {
                String[] spCol = item.toString().split("-");
                int start = Integer.parseInt(spCol[0]);
                int end = Integer.parseInt(spCol[1]);
                for (int i = start; i <= end; i++) {
                    mergeColumnIndex.add(i);
                }
            } else {
                int colIndex = Integer.parseInt(item.toString());
                mergeColumnIndex.add(colIndex);
            }

        }
        this.uniqueCol = uniqueCol;
        this.totalRow = totalRow;
    }

    @Override
    public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer rowIndex, Integer relativeRowIndex, Boolean isHead) {

    }

    @Override
    public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {

    }

    @Override
    public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
        //當(dāng)前行
        int curRowIndex = row.getRowNum();
        //每一行的最大列數(shù)
        short lastCellNum = row.getLastCellNum();
        //當(dāng)前行為開始合并行時,標(biāo)記
        if (curRowIndex == mergeRowIndex) {
            //賦初值 第一行
            firstRow = curRowIndex;
        }
        //開始合并位置
        if (curRowIndex > mergeRowIndex && !row.getCell(0).getStringCellValue().equals("")) {
            for (int i = 0; i < lastCellNum; i++) {
                if (mergeColumnIndex.contains(i)) {
                    //當(dāng)前行號 當(dāng)前行對象 合并的標(biāo)識位
                    mergeWithPrevAnyRow(writeSheetHolder.getSheet(), curRowIndex, row, uniqueCol);
                    break;//已經(jīng)進(jìn)入到合并單元格操作里面了,執(zhí)行一次就行
                }

            }
        }
    }

    public void mergeWithPrevAnyRow(Sheet sheet, int curRowIndex, Row row, int[] uniqueCol) {
        Object currentData = "";
        Object preData = "";
        for (int col : uniqueCol) {
            currentData = currentData + row.getCell(col).getStringCellValue();
            Row preRow = row.getSheet().getRow(curRowIndex - 1);
            preData = preData + preRow.getCell(col).getStringCellValue();
        }

        //判斷是否合并單元格
        boolean curEqualsPre = currentData.equals(preData);
        //判斷前一個和后一個相同 并且 標(biāo)識位相同
        if (curEqualsPre) {
            lastRow = curRowIndex;
            mergeCount++;
        }
        //excel過程中合并
        if (!curEqualsPre && mergeCount > 1) {
            mergeSheet(firstRow, lastRow, mergeColumnIndex, sheet);
            mergeCount = 1;
        }

        //excel結(jié)尾處合并
        if (mergeCount > 1 && totalRow == curRowIndex) {
            mergeSheet(firstRow, lastRow, mergeColumnIndex, sheet);
            mergeCount = 1;
        }
        //重置下一個要合并的行
        if (!curEqualsPre) {
            firstRow = curRowIndex;
        }

    }

    private void mergeSheet(int firstRow, int lastRow, List<Integer> mergeColumnIndex, Sheet sheet) {
        for (int colNum : mergeColumnIndex) {
            firstCol = colNum;
            lastCol = colNum;
            CellRangeAddress cellRangeAddress = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol);
            sheet.addMergedRegion(cellRangeAddress);

            // 設(shè)置合并后的單元格樣式為垂直居中
            CellStyle style = sheet.getWorkbook().createCellStyle();
            style.setVerticalAlignment(VerticalAlignment.CENTER);
            //style.setAlignment(HorizontalAlignment.CENTER);
            Cell mergedCell = sheet.getRow(firstRow).getCell(colNum, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
            mergedCell.setCellStyle(style);
        }
    }
}

日期格式轉(zhuǎn)換

EasyExcel => FastExcel ,導(dǎo)入支持多種時間格式

package com.vipsoft.base.util;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;

import cn.idev.excel.converters.Converter;
import cn.idev.excel.enums.CellDataTypeEnum;
import cn.idev.excel.metadata.GlobalConfiguration;
import cn.idev.excel.metadata.data.ReadCellData;
import cn.idev.excel.metadata.data.WriteCellData;
import cn.idev.excel.metadata.property.ExcelContentProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 日期格式轉(zhuǎn)換器
 */
public class ExcelDateConverter implements Converter<Date> {
    private static final Logger log = LoggerFactory.getLogger(ExcelDateConverter.class);
    // 定義所有要嘗試的日期格式
    SimpleDateFormat[] formats = {
            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"),
            new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"),
            new SimpleDateFormat("yyyy/MM/dd"),
            new SimpleDateFormat("yyyy-MM-dd"),
            new SimpleDateFormat("yyyy-MM"),
            new SimpleDateFormat("yyyy/MM"),
            new SimpleDateFormat("yyyyMMdd")
    };

    @Override
    public Class<Date> supportJavaTypeKey() {
        return Date.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }


    @Override
    public Date convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty,
                                  GlobalConfiguration globalConfiguration) throws Exception {
        String cellValue = "";
        if (cellData.getType().equals(CellDataTypeEnum.NUMBER)) {
            long cellIntValue = cellData.getNumberValue().longValue();
            if (cellIntValue > 19900100) {
                try {
                    // 1. 第一種解析,傳入的是數(shù)字形式的日期,形如yyyyMMdd
                    SimpleDateFormat originalFormat = new SimpleDateFormat("yyyyMMdd");
                    return originalFormat.parse(String.valueOf(cellIntValue));
                } catch (Exception e) {
                    log.warn("exception when parse numerical time with format yyyyMMdd");
                    cellValue=String.valueOf(cellIntValue);
                }
            }

            // 2. 第二種解析, excel是從1900年開始計(jì)算,最終通過計(jì)算與1900年間隔的天數(shù)計(jì)算目標(biāo)日期
            LocalDate localDate = LocalDate.of(1900, 1, 1);

            //excel 有些奇怪的bug, 導(dǎo)致日期數(shù)差2
            localDate = localDate.plusDays(cellIntValue - 2);

            // 轉(zhuǎn)換為ZonedDateTime(如果需要時區(qū)信息)
            ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
            return Date.from(zonedDateTime.toInstant());
        } else if (cellData.getType().equals(CellDataTypeEnum.STRING)) {
            // 3. 第三種解析
            Date date = null;
            cellValue = cellData.getStringValue();
            for (SimpleDateFormat format : formats) {
                try {
                    date = format.parse(cellValue);
                    if (date != null) {
                        // 這一步是將日期格式化為Java期望的格式
                        return date;
                    }
                } catch (Exception e) {
                    // 如果有異常,捕捉異常后繼續(xù)解析
                    //log.error(e.getMessage(), e);
                }
            }
        }
        // 沒轉(zhuǎn)成功,拋出異常
        throw new UnsupportedOperationException("The current operation is not supported by the current converter." + cellValue);
    }


    @Override
    public WriteCellData<?> convertToExcelData(Date value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dateValue = sdf.format(value);
        return new WriteCellData<>(dateValue);
    }
} 

接口代碼

導(dǎo)出代碼

package com.vipsoft.api.controller;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.Map;

/**
 * 企業(yè)信息
 */
@RestController
@RequestMapping("/detail")
public class CooperationDetailController extends BaseController {


  /**
     * 企業(yè)信息
     * 
     * @return
     */
    @PostMapping("/export")
    public void exportInfo(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, Object> param) {
        try {
            Page page = buildPage(param, CooperationInfo.class);
            QueryWrapper<SysOrganization> queryWrapper = buildQueryWrapper(SysOrganization.class, param);            
            cooperationDetailService.exportInfo(response, queryWrapper);
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
        }
    }
}

Service

@Service
public class SysOrganizationServiceImpl extends ServiceImpl<SysOrganizationMapper, SysOrganization> implements ISysOrganizationService {

    @Override
    public void exportInfo(HttpServletResponse response, QueryWrapper<SysOrganization> queryWrapper) {
        String templateFileName = "";
        try {
            templateFileName = cuworConfig.getFilePath() + "/template/企業(yè)導(dǎo)出模板.xlsx";
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            // 這里URLEncoder.encode可以防止中文亂碼 當(dāng)然和 FastExcel 沒有關(guān)系
            String fileName = URLEncoder.encode("企業(yè)數(shù)據(jù)", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            //獲取要導(dǎo)出的數(shù)據(jù) DTO
            List<SysOrganizationExcelDTO> dataList = data(queryWrapper);
            int mergeRowIndex = 2;                      // 從那一行開始合并  -- 跳過表頭
            int[] uniqueCol = {0, 7};                  //根據(jù)指定的列,確定相同的數(shù)據(jù)
            Object[] mergeColIndex = {"0-1", 6, 7};    //需要合并的列
            int totalRow = dataList.size() - 1 + mergeRowIndex;
            // 這里需要設(shè)置不關(guān)閉流
            ExcelCellMergeStrategy excelCellMergeStrategy = new ExcelCellMergeStrategy(mergeRowIndex, mergeColIndex, uniqueCol, totalRow);
            FastExcel.write(response.getOutputStream(), SysOrganizationExcelDTO.class)
                    .needHead(false)
                    .withTemplate(templateFileName)
                    .autoCloseStream(Boolean.FALSE)
                    .registerWriteHandler(excelCellMergeStrategy) //合并單元格
                    .sheet("企業(yè)數(shù)據(jù)")
                    .doWrite(dataList);
        } catch (Exception e) {
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            //異常時,向前端拋出 JSON 
            ApiResult result = new ApiResult(6001, "下載文件失敗 " + templateFileName + " " + e.getMessage());
            try {
                response.getWriter().println(PojoUtil.pojoToJson(result));
            } catch (IOException ex) {
                logger.error(ex.getMessage(), ex);
                throw new CustomException(ex.getMessage());
            }
        }
    }

    /**
     * 獲得要到出的數(shù)據(jù)
     */
    private List<SysOrganizationExcelDTO> data(QueryWrapper<SysOrganization>  queryWrapper) {
        IPage list = this.page(new Page(1, 10000), queryWrapper);
        List<SysOrganizationExcelDTO> result = new ArrayList<>();
        for (Object obj : list.getRecords()) {
            if (obj instanceof SysOrganization) {
                SysOrganization item = (SysOrganization) obj;
                SysOrganizationExcelDTO info = new SysOrganizationExcelDTO(); 
                BeanUtils.copyProperties(item, info); 
                //組裝數(shù)據(jù)
                result.add(info);
            }
        }
        return result;
    }
}  

DTO

package com.vipsoft.base.dto;


import cn.idev.excel.annotation.ExcelIgnore;
import cn.idev.excel.annotation.ExcelProperty;
import cn.idev.excel.annotation.format.DateTimeFormat;
import com.vipsoft.base.util.ExcelDateConverter;

import java.io.Serializable;
import java.util.Date;

/**
 * Excel 導(dǎo)出使用
 */
public class SysOrganizationExcelDTO implements Serializable {

    /**
     * 統(tǒng)一社會信用代碼
     */
    //@ExcelProperty(value = "統(tǒng)一社會信用代碼")
    @ExcelProperty(index = 0)
    private String unifiedSocialCode;

    /**
     * 機(jī)構(gòu)名稱
     */
    @ExcelProperty(index = 1)
    private String orgName; 

    /**
     * 崗位大類名稱
     */
    @ExcelProperty(index = 2)
    private String jobBigName;
    /**
     * 崗位中類名稱
     */
    @ExcelProperty(index = 3)
    private String jobMiddleName;
    /**
     * 崗位小類名稱
     */
    @ExcelProperty(index = 4)
    private String jobSmallName;
    /**
     * 崗位數(shù)量
     */
    @ExcelProperty(index = 5)
    private Integer jobQty;
	
    /**
     * 填報日期*
     */
    @ExcelProperty(index = 6, converter = ExcelDateConverter.class)
    private Date inputDate;
    /**
     * 填報人
     */
    @ExcelProperty(index = 7)
    private String inputUser;

    ......省略get set
 
}

到此這篇關(guān)于Java使用FastExcel實(shí)現(xiàn)合并單元格的文章就介紹到這了,更多相關(guān)Java FastExcel合并單元格內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java web如何解決瞬間高并發(fā)

    java web如何解決瞬間高并發(fā)

    這篇文章主要為大家詳細(xì)介紹了java web解決瞬間高并發(fā)的策略,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • 詳解Java的MyBatis框架中SQL語句映射部分的編寫

    詳解Java的MyBatis框架中SQL語句映射部分的編寫

    這篇文章主要介紹了Java的MyBatis框架中SQL語句映射部分的編寫,文中分為resultMap和增刪查改實(shí)現(xiàn)兩個部分來講解,需要的朋友可以參考下
    2016-04-04
  • Java實(shí)例講解Comparator的使用

    Java實(shí)例講解Comparator的使用

    我們先介紹一下comparator,我們后文稱為比較器。比較器實(shí)際上是一個實(shí)現(xiàn)了comparator interface是一個實(shí)例,在Arrays.sort方法我們可以提供這樣一個實(shí)例,即使被排序的object沒有實(shí)現(xiàn)comparable接口,我們也可以排序了
    2022-11-11
  • Spring MVC數(shù)據(jù)綁定概述及原理詳解

    Spring MVC數(shù)據(jù)綁定概述及原理詳解

    這篇文章主要介紹了Spring MVC數(shù)據(jù)綁定概述及原理詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-06-06
  • 如何實(shí)現(xiàn)自己的spring boot starter

    如何實(shí)現(xiàn)自己的spring boot starter

    這篇文章主要介紹了如何實(shí)現(xiàn)自己的spring boot starter,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-08-08
  • java中常用的json,jsonarray,map數(shù)據(jù)結(jié)構(gòu)與對象互轉(zhuǎn)詳解

    java中常用的json,jsonarray,map數(shù)據(jù)結(jié)構(gòu)與對象互轉(zhuǎn)詳解

    這篇文章主要為大家詳細(xì)介紹了java中常用的json,jsonarray,map數(shù)據(jù)結(jié)構(gòu)與對象互轉(zhuǎn)的相關(guān)方法,主要是FastJSON和Jackson兩種常用庫,有需要的小伙伴可以了解下
    2025-12-12
  • Mybatis一對多和多對一處理的深入講解

    Mybatis一對多和多對一處理的深入講解

    Mybatis可以通過關(guān)聯(lián)查詢實(shí)現(xiàn),關(guān)聯(lián)查詢是幾個表聯(lián)合查詢,只查詢一次,通過在resultMap里面的association,collection節(jié)點(diǎn)配置一對一,一對多的類就可以完成,這篇文章主要給大家介紹了關(guān)于Mybatis一對多和多對一處理的相關(guān)資料,需要的朋友可以參考下
    2021-09-09
  • Java實(shí)現(xiàn)在線語音識別

    Java實(shí)現(xiàn)在線語音識別

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)在線語音識別功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • java實(shí)現(xiàn)訂餐系統(tǒng)

    java實(shí)現(xiàn)訂餐系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)訂餐系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • Maven的安裝和環(huán)境變量配置過程

    Maven的安裝和環(huán)境變量配置過程

    文章介紹了如何下載、安裝和配置Maven,包括環(huán)境變量配置和阿里云鏡像的可選配置,此外,還展示了如何在IntelliJ IDEA中新建一個Maven項(xiàng)目
    2024-11-11

最新評論

南和县| 泸州市| 湘阴县| 武威市| 股票| 韶关市| 曲周县| 蚌埠市| 南充市| 翁源县| 九江县| 海城市| 嘉义县| 金堂县| 遂昌县| 宝应县| 吉木乃县| 靖江市| 故城县| 梅州市| 英德市| 宁乡县| 武安市| 绵阳市| 霍州市| 廉江市| 淮南市| 天柱县| 方山县| 永泰县| 铜梁县| 阜新| 定南县| 乐山市| 裕民县| 牙克石市| 库车县| 通河县| 墨竹工卡县| 江达县| 宣武区|