zoukankan      html  css  js  c++  java
  • excel导出工具包

    excel导出工具类

    package com.ljyq.central.common.util;
    
    import org.apache.commons.collections4.CollectionUtils;
    import org.apache.commons.collections4.MapUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.poi.hssf.usermodel.HSSFWorkbook;
    import org.apache.poi.poifs.filesystem.POIFSFileSystem;
    import org.apache.poi.ss.usermodel.*;
    import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    
    import javax.servlet.http.HttpServletResponse;
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.io.UnsupportedEncodingException;
    import java.net.URLEncoder;
    import java.nio.charset.StandardCharsets;
    import java.util.*;
    
    
    public final class Export {
    
    public static final boolean excel07 = true;
    public static final boolean excel03 = ! excel07;
    private static final String DEFAULT_SHEET_NAME = "工作表1";
    
    /**
    * 导出文件! 在 Controller 中调用!
    *
    * @param type 类型: csv 或 xls xlsx 三种, 传 null 则默认是 csv
    * @param name 导出的文件名, 若导出成 excel, sheet 名也是这个
    * @param titleMap 标题(key 为英文, value 为标题内容)
    * @param dataList 导出的数据(数组中的每个 object 都是一行, object 中的属性名与标题中的 key 相对)
    */
    public static void export ( Type type , String name , LinkedHashMap< String, String > titleMap ,
    List< ? > dataList , HttpServletResponse response ) throws IOException {
    if ( type == null ) type = Type.CSV;
    
    // 导出文件加上当前时间
    String fileName = encodeName( name ) + "." + type.getValue().toLowerCase();
    if ( type.isExcel() ) {
    LinkedHashMap linkedHashMap = new LinkedHashMap( Collections.singletonMap( name , dataList ) );
    exportXls( response , fileName , titleMap , linkedHashMap );
    } /*else if ("pdf".equalsIgnoreCase(type)) {
    // ...
    }*/ else {
    exportCsv( response , fileName , titleMap , dataList );
    }
    }
    
    public static String encodeName ( String name ) {
    String fileName = name + "-" + ( DateUtils.currentTimeString() );
    String userAgent = RequestUtils.getUserAgentHeader();
    if ( StringUtils.isNotBlank( userAgent ) && userAgent.contains( "Mozilla" ) ) {
    // Chrome, Firefox, Safari etc...
    fileName = new String( fileName.getBytes() , StandardCharsets.ISO_8859_1 );
    } else {
    try {
    fileName = URLEncoder.encode( fileName , StandardCharsets.UTF_8.name() );
    } catch ( UnsupportedEncodingException e ) {
    // ignore
    }
    }
    return fileName;
    }
    
    private static void setResponse ( HttpServletResponse response , String type , String fileName ) {
    response.setContentType( "text/" + type );
    response.setContentType( "application/octet-stream; charset=utf-8" );
    response.setHeader( "Content-Disposition" , "attachment;filename=" + fileName );
    }
    
    public static void exportDoc ( HttpServletResponse response , String fileName , String html ) throws IOException {
    // 将 html 导出成 doc 文档
    setResponse( response , "doc" , fileName );
    
    POIFSFileSystem fs = new POIFSFileSystem();
    fs.createDocument( new ByteArrayInputStream( html.getBytes( StandardCharsets.UTF_8 ) ) , "WordDocument" );
    fs.writeFilesystem( response.getOutputStream() );
    }
    
    
    public static void exportXls ( HttpServletResponse response , String fileName ,
    LinkedHashMap< String, String > titleMap ,
    LinkedHashMap< String, List< ? > > dataMap ) throws IOException {
    // 导出 excel
    setResponse( response , "xls" , fileName );
    exportXls( response.getOutputStream() , Type.is07Suffix( fileName ) , titleMap , dataMap );
    }
    
    public static void exportXls ( OutputStream outputStream ,
    boolean isExcel07 ,
    String sheetName ,
    LinkedHashMap< String, String > titleMap ,
    List< ? > dataList ) throws IOException {
    exportXls( outputStream ,
    isExcel07 ,
    titleMap ,
    new LinkedHashMap<>( Collections.singletonMap( sheetName , dataList ) ) );
    }
    
    public static void exportXls ( OutputStream outputStream ,
    LinkedHashMap< String, String > titleMap ,
    List< ? > dataList ) throws IOException {
    exportXls( outputStream ,
    excel03 ,
    titleMap ,
    new LinkedHashMap<>( Collections.singletonMap( DEFAULT_SHEET_NAME , dataList ) )
    );
    }
    
    
    public static void exportXls ( OutputStream outputStream ,
    boolean isExcel07 ,
    LinkedHashMap< String, String > titleMap ,
    List< ? > dataList ) throws IOException {
    exportXls( outputStream ,
    isExcel07 ,
    titleMap ,
    new LinkedHashMap<>( Collections.singletonMap( DEFAULT_SHEET_NAME , dataList ) ) );
    }
    
    /**
    * 导出Excel
    *
    * @param outputStream : 输出流
    * @param isExcel07 : 是否microsoft excel 2007(xlsx)
    * @param titleMap : 属性名为 key, 对应的标题为 value
    * @param dataMap : ( key : sheetname,value : sheet数据 ) , 如果你只要一个表,那么可以这样:new LinkedHashMap<>( Collections.singletonMap( sheetName , dataMap ) ) )
    * @throws IOException
    */
    public static void exportXls ( OutputStream outputStream , boolean isExcel07 ,
    LinkedHashMap< String, String > titleMap ,
    LinkedHashMap< String, List< ? > > dataMap ) throws IOException {
    exportXlsToWorkbook( isExcel07 , titleMap , dataMap ).write( outputStream );
    }
    
    public static Workbook exportXlsToWorkbook ( boolean isExcel07 ,
    LinkedHashMap< String, String > titleMap ,
    List< ? > dataList ) throws IOException {
    return ExportExcel.handle( isExcel07 ,
    titleMap ,
    new LinkedHashMap<>( Collections.singletonMap( DEFAULT_SHEET_NAME , dataList ) ) );
    }
    
    public static Workbook exportXlsToWorkbook ( boolean isExcel07 ,
    LinkedHashMap< String, String > titleMap ,
    LinkedHashMap< String, List< ? > > dataMap ) throws IOException {
    return ExportExcel.handle( isExcel07 , titleMap , dataMap );
    }
    
    
    public static void exportTxt ( HttpServletResponse response , String fileName , String content ) throws
    IOException {
    // 导出 txt
    setResponse( response , "plain" , fileName );
    response.getOutputStream().write( content.getBytes( StandardCharsets.UTF_8 ) );
    }
    
    public static void exportCsv ( HttpServletResponse response , String fileName ,
    LinkedHashMap< String, String > titleMap , List< ? > dataList ) throws IOException {
    String content = convertCsv( titleMap , dataList );
    
    // 导出 csv
    setResponse( response , "csv" , fileName );
    response.getOutputStream().write( content.getBytes( StandardCharsets.UTF_8 ) );
    
    POIFSFileSystem poifsFileSystem = new POIFSFileSystem();
    poifsFileSystem.createDocument( new ByteArrayInputStream( content.getBytes( "GBK" ) ) , "WordDocument" );
    poifsFileSystem.writeFilesystem( response.getOutputStream() );
    }
    
    private static String convertCsv ( LinkedHashMap< String, String > titleMap , List< ? > dataList ) {
    
    // 没有数据或没有标题, 返回一个内容为空的文件
    if ( MapUtils.isEmpty( titleMap ) || CollectionUtils.isEmpty( dataList ) ) return StringUtils.EMPTY;
    
    // 用英文逗号(,)隔开列, 用换行(
    )隔开行, 内容中包含了逗号的需要用双引号包裹, 若内容中包含了双引号则需要用两个双引号表示.
    StringBuilder sbd = new StringBuilder();
    int i = 0;
    for ( String title : titleMap.values() ) {
    sbd.append( handleCsvContent( title ) );
    i++;
    if ( i != titleMap.size() ) sbd.append( "," );
    }
    for ( Object data : dataList ) {
    sbd.append( "
    " );
    i = 0;
    for ( String title : titleMap.keySet() ) {
    sbd.append( handleCsvContent(
    ReflectionPlusUtils.invokeFieldGettersMethodToCustomizeString( data , title ) )
    );
    i++;
    if ( i != titleMap.size() ) sbd.append( "," );
    }
    }
    return sbd.toString();
    }
    
    private static String handleCsvContent ( String content ) {
    return """ + content.replace( """ , """" ) + """;
    }
    
    public static String addXlsSuffix ( String fileName ) {
    return StringPrivateUtils.getString( fileName ) + ".xls";
    }
    
    public static String addXlsxSuffix ( String fileName ) {
    return StringPrivateUtils.getString( fileName ) + ".xlsx";
    }
    
    public enum Type {
    MS03( "xls" ), MS07( "xlsx" ), CSV( "csv" );
    
    private String value;
    
    Type ( String value ) {
    this.value = value;
    }
    
    public static boolean is07Suffix ( String fileName ) {
    return fileName.toLowerCase().endsWith( Type.MS07.getValue().toLowerCase() );
    }
    
    public static boolean is03Suffix ( String fileName ) {
    return fileName.toLowerCase().endsWith( Type.MS03.getValue().toLowerCase() );
    }
    
    public String getValue () {
    return value;
    }
    
    public boolean isExcel () {
    return Arrays.asList( MS03 , MS07 ).contains( this );
    }
    }
    
    private static final class ExportExcel {
    /** excel 2003 的最大列数是 256 列, 2007 及以上版本是 16384 列 */
    private static final int CELL_TOTAL = 256;
    /** excel 2003 的最大行数是 65536 行, 等同于 (2 << 15) - 1, 2007 开始的版本是 1048576 行 */
    private static final int ROW_TOTAL = 65536;
    
    /** 标题行的字体大小 */
    private static final short HEAD_FONT_SIZE = 11;
    /** 其他内容的字体大小 */
    private static final short FONT_SIZE = 10;
    /** 行高. 要比上面的字体大一点! */
    private static final short ROW_HEIGHT = 15;
    
    private static boolean must07 ( int cellSize ) {
    return cellSize > CELL_TOTAL;
    }
    
    /**
    * 返回一个 excel 工作簿
    *
    * @param excel07 是否返回 microsoft excel 2007 的版本
    * @param titleMap 属性名为 key, 对应的标题为 value, 为了处理显示时的顺序, 因此使用 linkedHashMap
    * @param dataMap 以「sheet 名」为 key, 对应的数据为 value(每一行的数据为一个 Object)
    */
    private static Workbook handle ( boolean excel07 , LinkedHashMap< String, String > titleMap ,
    LinkedHashMap< String, List< ? > > dataMap ) {
    // 如果要导出的不是 07 的版本, 但是导出的列却大于 256 列, 则只能导出 07 版本
    if ( ! excel07 ) {
    excel07 = must07( titleMap.size() );
    }
    
    // 声明一个工作薄. HSSFWorkbook 是 Office 2003 的版本, XSSFWorkbook 是 2007
    Workbook workbook = excel07 ? new XSSFWorkbook() : new HSSFWorkbook();
    // 没有数据, 或者没有标题, 都直接返回
    if ( MapUtils.isEmpty( dataMap ) || MapUtils.isEmpty( titleMap ) ) return workbook;
    
    // 头样式
    CellStyle headStyle = createHeadStyle( workbook );
    // 内容样式
    CellStyle contentStyle = createContentStyle( workbook );
    
    // sheet
    Sheet sheet;
    //
    Row row;
    //
    Cell cell;
    // 表格数 行索引 列索引 数据起始索引 数据结束索引
    int sheetCount, rowIndex, cellIndex, fromIndex, toIndex;
    // 大小 数据
    int size;
    List< ? > excelList;
    
    for ( Map.Entry< String, List< ? > > entry : dataMap.entrySet() ) {
    // 当前 sheet 的数据
    excelList = entry.getValue();
    if ( CollectionUtils.isNotEmpty( excelList ) ) {
    // 一个 sheet 数据过多 excel 处理会出错, 分多个 sheet
    size = excelList.size();
    sheetCount = ( ( size % ROW_TOTAL == 0 ) ? ( size / ROW_TOTAL ) : ( size / ROW_TOTAL + 1 ) );
    for ( int i = 0 ; i < sheetCount ; i++ ) {
    // 构建 sheet, 带名字
    sheet = workbook.createSheet( entry.getKey() + ( sheetCount > 1
    ? ( "-" + ( i + 1 ) )
    : StringUtils.EMPTY ) );
    
    // 每个 sheet 的标题行
    rowIndex = 0;
    cellIndex = 0;
    row = sheet.createRow( rowIndex );
    row.setHeightInPoints( ROW_HEIGHT );
    // 每个 sheet 的标题行
    for ( String header : titleMap.values() ) {
    // 宽度自适应
    sheet.autoSizeColumn( cellIndex );
    cell = row.createCell( cellIndex );
    cell.setCellStyle( headStyle );
    cell.setCellValue( header );
    cellIndex++;
    }
    // 冻结第一行
    sheet.createFreezePane( 0 , 1 , 0 , 1 );
    
    // 每个 sheet 除标题行以外的数据
    fromIndex = ROW_TOTAL * i;
    toIndex = ( i + 1 == sheetCount ) ? size : ROW_TOTAL;
    for ( Object data : excelList.subList( fromIndex , toIndex ) ) {
    if ( data != null ) {
    rowIndex++;
    // 每行
    row = sheet.createRow( rowIndex );
    row.setHeightInPoints( ROW_HEIGHT );
    cellIndex = 0;
    for ( String value : titleMap.keySet() ) {
    String cellValue;
    if ( data instanceof Map ) {
    final Object obj = ( ( Map ) data ).get( value );
    cellValue = Objects.isNull( obj ) ? StringUtils.EMPTY : obj.toString();
    } else {
    cellValue =
    ReflectionPlusUtils.invokeFieldGettersMethodToCustomizeString( data ,
    value );
    }
    // 每列
    cell = row.createCell( cellIndex );
    cell.setCellStyle( contentStyle );
    cell.setCellValue( cellValue );
    cellIndex++;
    }
    }
    }
    }
    }
    }
    return workbook;
    }
    
    /** 头样式 */
    private static CellStyle createHeadStyle ( Workbook workbook ) {
    CellStyle style = workbook.createCellStyle();
    
    style.setAlignment( HorizontalAlignment.LEFT ); // 水平居左
    style.setVerticalAlignment( VerticalAlignment.CENTER ); // 垂直居中
    // style.setWrapText(true); // 自动换行
    
    Font font = workbook.createFont();
    font.setBold( true ); // 粗体
    font.setFontHeightInPoints( HEAD_FONT_SIZE );
    style.setFont( font );
    return style;
    }
    
    /** 内容样式 */
    private static CellStyle createContentStyle ( Workbook workbook ) {
    CellStyle style = workbook.createCellStyle();
    
    style.setAlignment( HorizontalAlignment.LEFT );
    style.setVerticalAlignment( VerticalAlignment.CENTER );
    
    Font font = workbook.createFont();
    font.setFontHeightInPoints( FONT_SIZE );
    style.setFont( font );
    return style;
    }
    }
    }
    View Code
  • 相关阅读:
    DataGrid 应用合集
    [转]UBB C#完全版
    IE 7中的快捷键
    DataGrid 单击变色,鼠标经过变色 部分代码
    17种正则表达式
    单无格内强制换行
    图片上传,并自动生成缩略图!
    layout_weight学习心得
    android 手势
    java陷进一
  • 原文地址:https://www.cnblogs.com/dayuss/p/11508125.html
Copyright © 2011-2022 走看看