使用建造者模式(Builder Pattern) 設計Excel導出場景,附源碼

目錄

建造者模式(Builder Pattern)簡單介紹:

常見Excel導出場景

常見Excel 導出編碼過程-結合過程查看代碼

本文中的Excel導出使用方式

使用建造者模式設計Excel 導出

源碼地址  https://github.com/fzmeng/Excelbuild


  1. 建造者模式(Builder Pattern)簡單介紹:

    1. 將一個複雜對象的構建和它的表示分離,使同樣的構建構成可以創建不同的表示。
      建造者模式也是屬於創建型模型,是23種GOF之一。

  2. 常見Excel導出場景

    1. 已確定數據源List<Object>  或者 List<Map<String,Object>>   情況(實體類型,數據量大小),瀏覽器直接導出文件流到本地 或 儲存至服務器某目錄下;
    2. 未確定數據源List<Object>  或者 List<Map<String,Object>>   情況(實體類型,數據量大小,是否分頁),但可知數據源獲取方式(SQL查詢,分頁數據請求接口等 ) ,瀏覽器直接導出文件流到本地 或 儲存至服務器某目錄下;
  3. 常見Excel 導出編碼過程-結合過程查看代碼

    1. 創建工作簿 HSSFWorkbook, XSSFWorkbook ,SXSSFWorkbook(本文使用此工作簿,它採用滑動窗口模式,避免OOM)
    2. 創建Sheet 表;
    3. 創建列寬;
    4. 創建樣式 - AbstractBuildStyle;
    5. 創建標題與表頭 - AbstractBuildTitle;
    6. 生成數據內容 - AbstractBuildContent;
  4. 本文中的Excel導出使用方式

  5. 
    
    
    
    package com.mfz.study.util.build;
    
    import com.alibaba.fastjson.JSONObject;
    import com.mfz.study.util.InvokeDataSource;
    import lombok.Data;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.http.HttpServletResponse;
    import java.util.ArrayList;
    import java.util.LinkedHashMap;
    import java.util.List;
    
    /**
     * @Description:
     * @Author mengfanzhu
     * @Date 2019/12/18 14:19
     * @Version 1.0
     */
    @RestController
    public class TestController {
    
        static List<ExcelExportModel> excelExportModels = new ArrayList<>();
        static List<LinkedHashMap<String, Object>> excelExportMaps = new ArrayList<>();
    
        static LinkedHashMap<String, Integer> columnTypeMap = new LinkedHashMap<String, Integer>() {{
            put("id", ExcelCellType.STRING.getCode());
            put("name", ExcelCellType.STRING.getCode());
            put("address", ExcelCellType.STRING.getCode());
        }};
    
    
        static LinkedHashMap<String, String> titleMap = new LinkedHashMap<String, String>() {{
            put("id", "標識");
            put("name", "名字");
            put("address", "地址");
        }};
    
    
        static {
            int max = 10000;
            for (int i = 0; i < max; i++) {
                ExcelExportModel excelExportModel = new ExcelExportModel();
                excelExportModel.setName("黎明" + i);
                excelExportModel.setAddress("地址" + i);
                excelExportModel.setId(i + "");
                excelExportModels.add(excelExportModel);
            }
    
            for (int i = 0; i < max; i++) {
                LinkedHashMap<String, Object> d = new LinkedHashMap<>();
                d.put("name", "黎明" + i);
                d.put("address", "北京朝陽" + i);
                d.put("id", "00001" + i);
                excelExportMaps.add(d);
            }
        }
    
        @Data
        public static class ExcelExportModel {
    
            private String id;
    
            private String name;
    
            private String address;
        }
    
        @GetMapping(value = "/export")
        public void export(HttpServletResponse response) {
            useWay1(response);
        }
    
        @GetMapping(value = "/export3")
        public void export3(HttpServletResponse response) {
            useWay3(response);
        }
    
        @GetMapping(value = "/export4")
        public void export4(HttpServletResponse response) {
            useWay4(response);
        }
    
    
        /**
         * invoke data
         *
         * @param response
         */
        private void useWay4(HttpServletResponse response) {
            ExcelExportModel param = new ExcelExportModel();
            param.setId("10");
            param.setName("我是反射獲取數據源");
            param.setAddress("反射類地址");
    
            new ExcelDirector()
                    .addFieldTitleTable(titleMap)
                    .setExcelFileName("反射獲取數據源文件.xlsx")
                    .setColumnTypeMap(columnTypeMap)
                    .setBoundInvokeClass(InvokeDataSource.class)
                    .setBoundInvokeMethodParamValues(JSONObject.toJSONString(param), 0, 1000)
                    .constructMapInvokeData().flush(response);
        }
    
        /**
         * Map 導出
         *
         * @param response
         */
        private void useWay3(HttpServletResponse response) {
            new ExcelDirector()
                    .addFieldTitleTable(titleMap)
                    .setData(excelExportMaps)
                    .setExcelFileName("c201900202")
                    //可不指定columnTypeMap ,默認爲String
    //                .setColumnTypeMap(columnTypeMap)
                    .constructMap()
                    .flush(response);
        }
    
    
        /**
         * model 1
         *
         * @param response
         */
        private void useWay1(HttpServletResponse response) {
            //實體對象導出示例
            new ExcelDirector()
                    .addFieldTitleTable(titleMap)
                    .setData(excelExportModels)
                    .setExcelFileName("測試Excel.xlsx")
                    .setTitles(new String[]{"北京統計", "20191229"})
                    .constructModel()
                    .flush(response);
        }
    }

     

  6. 使用建造者模式設計Excel 導出

    1. UML類圖結構:
    2. 源碼:
      1. pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.mfz.study</groupId>
	<artifactId>excelbuild</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>excelbuild</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>3.16</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>3.16</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.20</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

2. 相關代碼如下:

package com.mfz.study.util.build;

import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

import java.util.Map;

/**
 * @Description: 設置樣式庫-抽象
 * @Author mengfanzhu
 * @Date 2019/12/18 11:00
 * @Version 1.0
 */
public abstract class AbstractBuildStyle {

    /**
     * 任何實現類,如果定義的是內容樣式,存入map的key必須是這個,否則不生效
     */
    public static final String CONTENT_STYLE_KEY = "contentStyleKey";

    /**
     * 任何實現類,如果定義的是標題樣式且使用默認的設置Title方式,
     * 則存入map的key必須是這個,否則不生效,如果同時自定義了設置Title的實現,則不受這個限制
     */
    public static final String TITLE_STYLE_KEY = "titleStyleKey";

    /**
     * 任何實現類,如果定義的是表頭樣式,存入map的key必須是這個,否則不生效
     */
    public static final String HEAD_STYLE_KEY = "headStyleKey";

    /**
     * @param workbook 表格
     * @param styleMap 樣式庫
     */
    abstract void setStyle(SXSSFWorkbook workbook, Map<String,CellStyle> styleMap);
}



package com.mfz.study.util.build;

import lombok.Getter;
import lombok.Setter;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.xssf.streaming.SXSSFSheet;

import java.util.Map;

/**
 * @Description: 設置標題抽象
 * @Author mengfanzhu
 * @Date 2019/12/18 10:55
 * @Version 1.0
 */
@Getter
@Setter
public abstract class AbstractBuildTitle {

    /**
     * @param sheet           表格
     * @param titles          標題數組
     * @param heads           表頭列數組
     * @param styleMap        樣式庫
     * @param fieldTitleTable 列對應表頭名
     */
    abstract void setTitle(SXSSFSheet sheet, String[] titles, Map<String, CellStyle> styleMap, String[] heads, Map<String, String> fieldTitleTable);
}



package com.mfz.study.util.build;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.xssf.streaming.SXSSFSheet;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Description: 設置內容-抽象
 * @Author mengfanzhu
 * @Date 2019/12/18 11:11
 * @Version 1.0
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public abstract class AbstractBuildContent {

    Map<String, CellStyle> styleMap;

    SXSSFSheet sheet;

    AbstractGetFieldValue abstractGetFieldValue;

    /**
     * @param data
     * @param columns
     * @param columnTypes
     */
    abstract void setContent(Collection data, String[] columns, LinkedHashMap<String, Integer> columnTypes);
}


package com.mfz.study.util.build;

/**
 * @Description: 獲得屬性值抽象
 * @Author mengfanzhu
 * @Date 2019/12/18 10:35
 * @Version 1.0
 */
public abstract class AbstractGetFieldValue {

    /**
     * 獲取屬性值方法
     * @param obj 反射對象
     * @param fieldName 屬性名
     * @return
     */
    abstract Object getFieldValue(Object obj,String fieldName);
}


package com.mfz.study.util.build;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Description: 建造者模式-抽象建造者
 * @Author mengfanzhu
 * @Date 2019/12/18 11:24
 * @Version 1.0
 */
@Slf4j
public abstract class AbstractExcelBuilder {


    /**
     * 數據主體開始行下標
     */
    int rowStartIndex = 0;

    /**
     * excel名稱
     */
    String excelFileName;

    /**
     * 工作對象
     */
    SXSSFWorkbook workbook;

    /**
     * 表格
     */
    SXSSFSheet sheet;

    /**
     * 樣式庫
     */
    Map<String, CellStyle> styleMap = new HashMap<>();

    /**
     * 屬性-標題對照
     */
    LinkedHashMap<String, String> fieldTitleTable = new LinkedHashMap<>();

    /**
     * 獲取屬性值
     */
    AbstractGetFieldValue abstractGetFieldValue;

    /**
     * 設置樣式
     */
    AbstractBuildStyle abstractBuildStyle;

    /**
     * 設置標題+表頭
     */
    AbstractBuildTitle abstractBuildTitle;
    /**
     * 設置內容
     */
    AbstractBuildContent content;

    /**
     * 數據源所在類,需要實現接口
     *
     * @see BaseSetContentInterface
     */
    Class invokeClass;

    /**
     * 數據源所在方法,入參
     *
     * @see BaseSetContentInterface
     */
    String methodParamJson;
    Integer methodParamLimitStart;
    Integer methodParamLimitSize;

    void addFieldTitleTable(String fieldName, String titleName) {
        fieldTitleTable.put(fieldName, titleName);
    }

    /**
     * 建造工作對象
     *
     * @param wb
     * @return
     */
    abstract AbstractExcelBuilder buildWorkbook(SXSSFWorkbook wb);

    /**
     * 建造表格
     *
     * @param sheetName
     * @return
     */
    abstract AbstractExcelBuilder buildSheet(String sheetName);

    /**
     * @param data               數據源
     * @param heads              表頭
     * @param columnTypeMap      列對應數據類型
     * @param abstractSetContent
     * @return
     * @see AbstractBuildContent
     */
    abstract AbstractExcelBuilder buildContent(Collection data, String[] heads, LinkedHashMap<String, Integer> columnTypeMap, Class<? extends AbstractBuildContent> abstractSetContent);

    /**
     * 構建標題+表頭
     *
     * @param titles
     * @param heads
     * @return
     */
    abstract AbstractExcelBuilder buildTitlesAndHeads(String[] titles, String[] heads);

    /**
     * 文件名稱
     *
     * @param excelFileName
     * @return
     */
    abstract AbstractExcelBuilder buildExcelFileName(String excelFileName);

    abstract AbstractExcelBuilder buildStyle();

    /**
     * @param clazz
     * @return
     * @see BaseSetContentInterface
     */
    abstract AbstractExcelBuilder buildInvokeClass(Class clazz);

    /**
     * @param methodParamJson
     * @param methodParamLimitStart
     * @param methodParamLimitSize
     * @return
     * @see BaseSetContentInterface
     */
    abstract AbstractExcelBuilder buildInvokeMethodParamValue(String methodParamJson, Integer methodParamLimitStart, Integer methodParamLimitSize);

    /**
     * 輸出流
     *
     * @param response
     */
    abstract void flush(HttpServletResponse response);

    abstract void flush(HttpServletResponse response, String excelFileName);


    AbstractExcelBuilder buildColumn(int columnSize, boolean isAutoColumnWidth) {
        if (columnSize == 0) {
            return this;
        }
        if (isAutoColumnWidth) {
            for (int i = 0; i < columnSize; i++) {
                sheet.autoSizeColumn(i);
            }
            return this;
        }
        for (int i = 0; i < columnSize; i++) {
            sheet.setDefaultColumnWidth(i);
        }

        return this;
    }

    /**
     * 獲取屬性值的方式
     *
     * @param getFieldValue
     */
    void getFieldValueImpl(AbstractGetFieldValue getFieldValue) {
        if (null == getFieldValue) {
            this.abstractGetFieldValue = new DefaultGetValue();
        } else {
            this.abstractGetFieldValue = getFieldValue;
        }
    }

    void setStyleImpl(AbstractBuildStyle setStyle) {
        if (null == setStyle) {
            this.abstractBuildStyle = new DefaultBuildStyle();
        } else {
            this.abstractBuildStyle = setStyle;
        }
    }

    void setTitleImpl(AbstractBuildTitle setTitle) {
        if (null == setTitle) {
            this.abstractBuildTitle = new DefaultBuildTitle();
        } else {
            this.abstractBuildTitle = setTitle;
        }
    }

    void setContentImpl(Class<? extends AbstractBuildContent> abstractSetContent) {
        try {
            if (null == abstractSetContent) {
                this.content = new DefaultBuildContentModel(styleMap, sheet, abstractGetFieldValue).initParams(rowStartIndex);
                return;
            }
            AbstractBuildContent content = abstractSetContent.newInstance();
            if (content instanceof DefaultBuildContentInvokeData) {
                this.content = new DefaultBuildContentInvokeData(styleMap, sheet, abstractGetFieldValue)
                        .initParams(invokeClass, methodParamJson, methodParamLimitStart, methodParamLimitSize, rowStartIndex);
            } else if (content instanceof DefaultBuildContentMap) {
                this.content = new DefaultBuildContentMap(styleMap, sheet, abstractGetFieldValue).initParams(rowStartIndex);
            } else if (content instanceof DefaultBuildContentModel) {
                this.content = new DefaultBuildContentModel(styleMap, sheet, abstractGetFieldValue).initParams(rowStartIndex);
            } else {
                throw new IllegalArgumentException("Invalid AbstractBuildContent class: " + abstractSetContent.getName());
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public SXSSFWorkbook getWorkbook() {
        return workbook;
    }
}

package com.mfz.study.util.build;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;

import java.awt.Color;
import java.util.Map;

/**
 * @Description: 設置樣式-默認
 * @Author mengfanzhu
 * @Date 2019/12/18 11:05
 * @Version 1.0
 */
public class DefaultBuildStyle extends AbstractBuildStyle {

    private static Color blue = new Color(135, 206, 255);

    @Override
    void setStyle(SXSSFWorkbook workbook, Map<String, CellStyle> styleMap) {
        XSSFCellStyle style1 = (XSSFCellStyle) workbook.createCellStyle();
        /**
         * 標題樣式
         */
        // 前景色(藍色)
        XSSFColor myColor0= new XSSFColor(blue);
        style1.setFillForegroundColor(myColor0);
        // 設置單元格填充樣式
        style1.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        // 設置單元格邊框
        style1.setBorderBottom(BorderStyle.THIN);
        style1.setBorderLeft(BorderStyle.THIN);
        style1.setBorderRight(BorderStyle.THIN);
        style1.setBorderTop(BorderStyle.THIN);
        style1.setAlignment(HorizontalAlignment.CENTER);
        // 生成一個字體
        XSSFFont font0 = (XSSFFont) workbook.createFont();
        font0.setFontHeightInPoints((short) 14);
        font0.setBold(true);
        // 把字體應用到當前的樣式
        style1.setFont(font0);
        styleMap.put(TITLE_STYLE_KEY, style1);

        /**
         * 表頭樣式
         */
        // 生成一個字體
        XSSFFont font = (XSSFFont) workbook.createFont();
        font.setFontHeightInPoints((short) 12);
        font.setBold(true);
        // 把字體應用到當前的樣式
        style1.setFont(font);
        styleMap.put(HEAD_STYLE_KEY, style1);

        /**
         * 內容樣式
         */
        XSSFCellStyle style2 = (XSSFCellStyle) workbook.createCellStyle();
        XSSFColor white = new XSSFColor(Color.WHITE);
        style2.setFillBackgroundColor(white);
        style2.setBorderBottom(BorderStyle.THIN);
        style2.setBorderLeft(BorderStyle.THIN);
        style2.setBorderRight(BorderStyle.THIN);
        style2.setBorderTop(BorderStyle.THIN);
        style2.setAlignment(HorizontalAlignment.CENTER);
        style2.setVerticalAlignment(VerticalAlignment.CENTER);
        // 生成另一個字體
        XSSFFont font2 = (XSSFFont) workbook.createFont();
        font2.setBold(false);
        // 把字體應用到當前的樣式
        style2.setFont(font2);
        styleMap.put(CONTENT_STYLE_KEY, style2);
    }
}




package com.mfz.study.util.build;

import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.springframework.util.Assert;

import java.util.Map;

/**
 * @Description: 默認-設置標題-表頭
 * @Author mengfanzhu
 * @Date 2019/12/18 10:57
 * @Version 1.0
 */
public class DefaultBuildTitle extends AbstractBuildTitle {

    @Override
    void setTitle(SXSSFSheet sheet, String[] titles, Map<String, CellStyle> styleMap, String[] heads, Map<String, String> fieldTitleTable) {
        int rowIndex = 0;
        if (null != titles && titles.length != 0) {
            SXSSFRow rowTitle = sheet.createRow(rowIndex);

            for (int i = 0, j = titles.length; i < j; i++) {
                SXSSFCell cell = rowTitle.createCell(i);
                cell.setCellType(CellType.STRING);
                cell.setCellStyle(styleMap.get(AbstractBuildStyle.TITLE_STYLE_KEY));
                cell.setCellValue(titles[i]);
            }

            rowIndex++;
        }

        if (null != heads && heads.length != 0) {
            Assert.notEmpty(fieldTitleTable, "fieldTitleTable不能爲空!");

            SXSSFRow rowHead = sheet.createRow(rowIndex);
            for (int i = 0, j = heads.length; i < j; i++) {
                SXSSFCell cell = rowHead.createCell(i);
                cell.setCellType(CellType.STRING);
                cell.setCellStyle(styleMap.get(AbstractBuildStyle.HEAD_STYLE_KEY));

                XSSFRichTextString textString = new XSSFRichTextString(fieldTitleTable.get(heads[i]));
                cell.setCellValue(textString);
            }
        }
    }
}




package com.mfz.study.util.build;

/**
 * @Description: 默認獲取屬性值
 * @Author mengfanzhu
 * @Date 2019/12/18 10:36
 * @Version 1.0
 */
public class DefaultGetValue extends AbstractGetFieldValue{

    @Override
    Object getFieldValue(Object obj, String fieldName) {
        if(null == fieldName){
            return "";
        }
        return ReflectingHelper.getValueByField(obj,fieldName.toString());
    }
}




package com.mfz.study.util.build;


import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;

/**
 * @Description: 反射輔助類
 * @Author mengfanzhu
 * @Date 2019/12/18 10:38
 * @Version 1.0
 */
@Slf4j
public abstract class ReflectingHelper {

    public static Object getValueByField(Object obj, String fieldName) {
        if (obj == null || StringUtils.isEmpty(fieldName)) {
            return null;
        }

        Field field = getFieldByFieldName(obj, fieldName);
        Object val = null;

        if (!field.isAccessible()) {
            field.setAccessible(true);
        }
        try {
            val = field.get(obj);
            return val;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            log.error("反射輔助類-獲取值異常 " + e.toString());
        } finally {
            field.setAccessible(false);
        }
        return null;
    }

    /**
     * @param obj
     * @param fieldName
     * @return
     */
    public static Field getFieldByFieldName(Object obj, String fieldName) {
        for (Class<?> superClass = obj.getClass(); superClass != T.class; superClass = superClass.getSuperclass()) {
            try {
                return superClass.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
                log.error("反射輔助類-getFieldByFieldName-Exception:" + e.toString());
            }
        }
        return null;
    }
}
package com.mfz.study.util.build;

import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Description: 內容設置-默認-處理Model 類型數據源
 * @Author mengfanzhu
 * @Date 2019/12/18 11:14
 * @Version 1.0
 */
@Slf4j
@NoArgsConstructor
public class DefaultBuildContentModel extends AbstractBuildContent {

    private int rowStartIndex = 0;

    public DefaultBuildContentModel(Map<String, CellStyle> styleMap, SXSSFSheet sheet, AbstractGetFieldValue abstractGetFieldValue) {
        super(styleMap, sheet, abstractGetFieldValue);
    }

    public DefaultBuildContentModel initParams(int rowStartIndex) {
        this.rowStartIndex = rowStartIndex;
        return this;
    }

    @Override
    void setContent(Collection data, String[] columns, LinkedHashMap<String, Integer> columnTypes) {
        modelHandler(data, columns);
    }

    private void modelHandler(Collection data, String[] columns) {
        Assert.notEmpty(columns, "columns cannot be null");
        if (CollectionUtils.isEmpty(data)) {
            return;
        }
        log.info("modelHandler start");
        SXSSFRow row = null;
        SXSSFCell cell = null;
        Object fieldValue = null;
        XSSFRichTextString xssfVal = null;
        Iterator iter = data.iterator();

        while (iter.hasNext()) {
            rowStartIndex++;

            row = sheet.createRow(rowStartIndex);
            Object t = iter.next();
            for (int i = 0, j = columns.length; i < j; i++) {
                cell = row.createCell(i);
                cell.setCellType(CellType.STRING);
                cell.setCellStyle(styleMap.get(AbstractBuildStyle.CONTENT_STYLE_KEY));

                fieldValue = abstractGetFieldValue.getFieldValue(t, columns[i]);
                xssfVal = new XSSFRichTextString(String.valueOf(fieldValue));
                cell.setCellValue(xssfVal);
            }
        }
    }
}



package com.mfz.study.util.build;


public enum ExcelCellType {

    STRING(1),

    DECIMAL(2),

    _NONE(3),

    TIME(4),

    DATE(5);

    private final int code;

    ExcelCellType(int code) {
        this.code = code;
    }

    public static ExcelCellType getByCode(int code) {
        for (ExcelCellType type : values()) {
            if (type.code == code) {
                return type;
            }
        }
        throw new IllegalArgumentException("Invalid ExcelCellType code: " + code);
    }

    public int getCode() {
        return code;
    }

}



package com.mfz.study.util.build;

import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Description: 內容設置-默認-處理Map 類型數據源
 * @Author mengfanzhu
 * @Date 2019/12/18 11:14
 * @Version 1.0
 */
@Slf4j
@NoArgsConstructor
public class DefaultBuildContentMap extends AbstractBuildContent {

    private int rowStartIndex = 0;

    public DefaultBuildContentMap(Map<String, CellStyle> styleMap, SXSSFSheet sheet, AbstractGetFieldValue abstractGetFieldValue) {
        super(styleMap, sheet, abstractGetFieldValue);
    }

    public DefaultBuildContentMap initParams(int rowStartIndex){
        this.rowStartIndex = rowStartIndex;
        return this;
    }

    @Override
    void setContent(Collection data, String[] columns, LinkedHashMap<String, Integer> columnTypes) {
        mapHandler(data, columnTypes);
    }


    public void mapHandler(Collection data, LinkedHashMap<String, Integer> columnTypes) {
        Assert.notEmpty(columnTypes, "columnTypes cannot be null");
        if (CollectionUtils.isEmpty(data)) {
            return;
        }
        log.info("mapHandler start");
        SXSSFRow row = null;
        SXSSFCell cell = null;
        Iterator iter = data.iterator();
        int cellIndex = 0;
        Object fieldValue = null;
        Integer fieldType = null;
        //row loop
        while (iter.hasNext()) {
            Object t = iter.next();
            if (!(t instanceof Map)) {
                throw new IllegalArgumentException("DefaultBuildContentMap->data type must is List<Map<String,Object>> !");
            }
            rowStartIndex++;
            cellIndex = 0;
            row = sheet.createRow(rowStartIndex);
            Map<String, Object> map = (Map<String, Object>) t;
            //cell loop
            for (String fieldName : columnTypes.keySet()) {
                fieldValue = map.get(fieldName);
                if(null == fieldValue){
                    cellIndex++;
                    continue;
                }
                cell = row.createCell(cellIndex);
                cell.setCellType(CellType.STRING);
                cell.setCellStyle(styleMap.get(AbstractBuildStyle.CONTENT_STYLE_KEY));
                fieldType = columnTypes.get(fieldName);
                switch (ExcelCellType.getByCode(fieldType)) {
                    case STRING:
                        if (fieldValue instanceof String) {
                            String cellValue = String.valueOf(fieldValue);
                            cell.setCellValue(cellValue);
                        }
                        break;
                    case DECIMAL:
                        if (fieldValue instanceof BigDecimal) {
                            BigDecimal cellValue = (BigDecimal) fieldValue;
                            cellValue.setScale(2, BigDecimal.ROUND_DOWN);
                            cell.setCellValue(cellValue.toString());
                        }
                        break;
                    case _NONE:
                        break;
                    case TIME:
                        Timestamp resultTime = (Timestamp) fieldValue;
                        cell.setCellValue(getSimpleStringDate(resultTime));
                        break;
                    case DATE:
                        Date resultDate = (Date) fieldValue;
                        cell.setCellValue(getSimpleStringDate(resultDate));
                        break;
                }
                cellIndex++;
            }

        }
    }

    public static String getSimpleStringDate(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        return sdf.format(date);
    }
}


package com.mfz.study.util.build;

import com.mfz.study.util.SpringContextHolder;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.springframework.context.ApplicationContext;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Description: 內容設置-默認-處理Model 類型數據源
 * @Author mengfanzhu
 * @Date 2019/12/18 11:14
 * @Version 1.0
 */
@Slf4j
@NoArgsConstructor
public class DefaultBuildContentInvokeData extends AbstractBuildContent {

    private int rowStartIndex = 0;
    private Class invokeClass;

    /**
     * @see BaseSetContentInterface
     */
    private String json;
    private Integer limitStart;
    private Integer limitSize;

    public DefaultBuildContentInvokeData(Map<String, CellStyle> styleMap, SXSSFSheet sheet, AbstractGetFieldValue abstractGetFieldValue) {
        super(styleMap, sheet, abstractGetFieldValue);
    }

    public DefaultBuildContentInvokeData initParams(Class invokeClass, String methodParamJson, Integer methodParamLimitStart, Integer methodParamLimitSize, int rowStartIndex) {
        this.rowStartIndex = rowStartIndex;
        this.invokeClass = invokeClass;
        this.json = methodParamJson;
        this.limitStart = methodParamLimitStart;
        this.limitSize = methodParamLimitSize;
        return this;
    }

    @Override
    void setContent(Collection data, String[] columns, LinkedHashMap<String, Integer> columnTypes) {
        try {
            if (!(invokeClass.newInstance() instanceof BaseSetContentInterface)) {
                throw new Exception("DefaultBuildContentInvokeData.invokeClass need to implement BaseSetContentInterface !");
            }
            log.info("DefaultBuildContentInvokeData setContent start,invokeClasss is {},json is {},limitStart is {},limitSize is {} .", invokeClass, json, limitStart, limitSize);

            Method invokeMethod = BaseSetContentInterface.class.getMethods()[0];

            ApplicationContext context = SpringContextHolder.getApplicationContext();
            Object bean = context.getBean(invokeClass);
            /**
             * 給實例化的類注入需要的bean (@Autowired) ,如果不注入,被@Autowired註解的變量會報空指針
             */
            context.getAutowireCapableBeanFactory().autowireBean(bean);
            data = (Collection) invokeMethod.invoke(bean, json, limitStart, limitSize);

            DefaultBuildContentMap defaultSetContentMap = new DefaultBuildContentMap(styleMap, sheet, abstractGetFieldValue).initParams(rowStartIndex);
            for (; data.size() > 0;
                 limitStart += limitSize, data = (Collection) invokeMethod.invoke(bean, json, limitStart, limitSize)) {
                defaultSetContentMap.mapHandler(data, columnTypes);
            }
        } catch (Exception e) {
            log.error("DefaultBuildContentInvokeData exception", e.getMessage());
        }
    }
}


package com.mfz.study.util.build;

import java.util.List;
import java.util.Map;

/**
 * @Description: invokeData 需要實現此接口
 * @Author mengfanzhu
 * @Date 2019/12/20 10:11
 * @Version 1.0
 */
public interface BaseSetContentInterface {

    /**
     * @param json       數據構造入參
     * @param limitStart 數據分頁開始
     * @param size       每頁數據量
     * @return
     * @see DefaultBuildContentInvokeData
     */
    List<? extends Map<String, Object>> getExcelExportData(String json, Integer limitStart, Integer size);
}
package com.mfz.study.util.build;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Collection;
import java.util.LinkedHashMap;

/**
 * @Description: 建造者模式-具體建造者
 * @Author mengfanzhu
 * @Date 2019/12/18 11:39
 * @Version 1.0
 */
@Slf4j
public class ExcelBuilder extends AbstractExcelBuilder {

    /**
     * 構建滑動窗口數
     * new SXSSFWorkbook() -> 默認爲100
     */
    private static final Integer ROW_ACCESS_WINDOWSIZE = 200;

    @Override
    AbstractExcelBuilder buildWorkbook(SXSSFWorkbook wb) {
        if (null == workbook) {
            workbook = new SXSSFWorkbook(ROW_ACCESS_WINDOWSIZE);
        } else {
            workbook = wb;
        }
        return this;
    }

    @Override
    AbstractExcelBuilder buildSheet(String sheetName) {
        if (StringUtils.isEmpty(sheetName)) {
            sheetName = "sheet1";
        }
        sheet = workbook.createSheet(sheetName);
        return this;
    }

    @Override
    AbstractExcelBuilder buildContent(Collection data, String[] heads, LinkedHashMap<String, Integer> columnTypeMap, Class<? extends AbstractBuildContent> abstractSetContent) {
        setContentImpl(abstractSetContent);
        this.content.setContent(data, heads, columnTypeMap);
        return this;
    }

    @Override
    AbstractExcelBuilder buildTitlesAndHeads(String[] titles, String[] heads) {
        Assert.notEmpty(heads, "buildTitlesAndHeads->heads cannot be null");
        if (null != titles && titles.length > 0) {
            super.rowStartIndex = 1;
        }
        abstractBuildTitle.setTitle(sheet, titles, styleMap, heads, fieldTitleTable);
        return this;
    }

    @Override
    AbstractExcelBuilder buildExcelFileName(String excelFileName) {
        Assert.notNull(excelFileName, "excelFileName cannot be null");
        return this;
    }

    @Override
    AbstractExcelBuilder buildStyle() {
        abstractBuildStyle.setStyle(workbook, styleMap);
        return this;
    }

    @Override
    AbstractExcelBuilder buildInvokeClass(Class clazz) {
        super.invokeClass = clazz;
        return this;
    }

    @Override
    AbstractExcelBuilder buildInvokeMethodParamValue(String methodParamJson, Integer methodParamLimitStart, Integer methodParamLimitSize) {
        super.methodParamJson = methodParamJson;
        super.methodParamLimitStart = methodParamLimitStart;
        super.methodParamLimitSize = methodParamLimitSize;
        return this;
    }


    /**
     * 設定每次從內存讀多少
     */
    private static byte[] buff = new byte[2048];

    @Override
    void flush(HttpServletResponse response) {
        flush(response, this.excelFileName);
    }

    @Override
    void flush(HttpServletResponse response, String excelFileName) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            workbook.write(os);
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.toString());
        }
        //設置response參數,可以打開下載頁面
        packResponse(response, excelFileName);
        try (
                // 封裝爲緩衝,減少讀寫次數,提高效率
                BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(os.toByteArray()));
                BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
        ) {
            //循環從內存讀取,並寫到Resonse響應流中
            int bytesRead;
            while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                bos.write(buff, 0, bytesRead);
            }
        } catch (IOException e) {
            log.error(e.toString());
        } finally {
            // 將此workbook對應的臨時文件刪除
            if (null != workbook) {
                workbook.dispose();
            }
        }
    }

    private void packResponse(HttpServletResponse response, String excelFileName) {
        try {
            if(StringUtils.isEmpty(excelFileName)){
                excelFileName = "excel-"+System.currentTimeMillis()+".xlsx";
            }
            response.reset();
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + new String(excelFileName.getBytes(), "iso-8859-1"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}





package com.mfz.study.util.build;

import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Set;

/**
 * @Description: 建造者模式-負責規範流程
 * @Author mengfanzhu
 * @Date 2019/12/18 13:59
 * @Version 1.0
 */
public class ExcelDirector {

    private AbstractExcelBuilder abstractExcelBuilder = new ExcelBuilder();

    private String sheetName;

    private String excelFileName;

    private String[] heads;

    private String[] titles;

    private LinkedHashMap<String, Integer> columnTypeMap;

    private Collection data;

    private SXSSFWorkbook workbook;

    private boolean isAutoColumnWidth = false;

    private Integer columnSize = null;

    /**
     * 數據源所在類,方法入參
     * implements
     *
     * @see BaseSetContentInterface
     */
    private Class clazz;
    private String methodParamJson;
    private Integer methodParamLimitStart;
    private Integer methodParamLimitSize;

    public ExcelDirector() {
        overrideDefaultGetFieldValue(null)
                .overrideDefaultSetTitle(null)
                .overrideDefaultSetStyle(null);
    }

    /**
     * 構建一個對象的流程
     *
     * @return
     * @see TestController
     */
    public ExcelDirector constructModel() {
        Assert.notNull(heads, "constructModel -> heads need to do ");
        Assert.notNull(data, "constructModel -> data need to do ");
        abstractExcelBuilder
                .buildWorkbook(workbook)
                .buildSheet(sheetName)
                .buildColumn(columnSize, isAutoColumnWidth)
                .buildStyle()
                .buildTitlesAndHeads(titles, heads)
                .buildExcelFileName(excelFileName)
                .buildContent(data, heads, null, DefaultBuildContentModel.class);
        return this;
    }

    /**
     * //指定列對應類型
     * LinkedHashMap<String, Integer> columnTypeMap = new LinkedHashMap<>();
     * columnTypeMap.put("id", 1); //1 -> String
     * columnTypeMap.put("name", 1);
     * columnTypeMap.put("address", 1);
     * //指定表頭
     * LinkedHashMap<String, String> titleMap = new LinkedHashMap<>();
     * titleMap.put("id", "唯一標識符");
     * titleMap.put("name", "名字");
     * titleMap.put("address", "地址");
     * <p>
     * new ExcelDirector()
     * .addFieldTitleTable(titles)
     * //可不指定columnTypeMap 默認爲String
     * .setColumnTypeMap(columnTypeMap)
     * .setData(result)
     * .setExcelFileName(filename)
     * .constructMap()
     * .flush(response);
     * <p>
     * 構建一個Map數據源的流程
     *
     * @return
     * @see TestController
     */
    public ExcelDirector constructMap() {
        if (columnTypeMap == null || columnTypeMap.size() != columnSize) {
            columnTypeMap = new LinkedHashMap<>();
            for (String fieldName : heads) {
                columnTypeMap.put(fieldName, CellType.STRING.getCode());
            }
        }
        Assert.notNull(heads, "constructMap -> heads need to do ");
        Assert.notNull(columnTypeMap, "constructMap -> columnTypeMap need to do ");
        Assert.notNull(data, "constructMap -> data need to do ");
        abstractExcelBuilder
                .buildWorkbook(workbook)
                .buildSheet(sheetName)
                .buildColumn(columnSize, isAutoColumnWidth)
                .buildStyle()
                .buildTitlesAndHeads(titles, heads)
                .buildExcelFileName(excelFileName)
                .buildContent(data, null, columnTypeMap, DefaultBuildContentMap.class);
        return this;
    }


    /**
     * @return
     * @see TestController
     * 構建一個Map 類型,反射數據源的流程
     * 示例:
     * 1.
     * //指定列對應類型
     * LinkedHashMap<String, Integer> columnTypeMap = new LinkedHashMap<>();
     * columnTypeMap.put("id", 1); //1 -> String
     * columnTypeMap.put("name", 1);
     * columnTypeMap.put("address", 1);
     * //指定表頭
     * LinkedHashMap<String, String> titleMap = new LinkedHashMap<>();
     * titleMap.put("id", "唯一標識符");
     * titleMap.put("name", "名字");
     * titleMap.put("address", "地址");
     * <p>
     * SXSSFWorkbook wb = new ExcelDirector()
     * .addFieldTitleTable(titleMap)
     * .setColumnTypeMap(columnTypeMap)
     * .setBoundInvokeClass(this.getClass())
     * .setBoundInvokeMethodParamValues(JSONObject.toJSONString(params), 0, 5000)
     * .constructMapInvokeData()
     * .getWorkbook();
     * <p>
     * 2. 直接導出
     * new ExcelDirector()
     * .addFieldTitleTable(titleMap)
     * .setTitles("sheet1")
     * .setColumnTypeMap(columnTypeMap)
     * .setBoundInvokeClass(this.getClass())
     * .setBoundInvokeMethodParamValues(JSONObject.toJSONString(params),0,1000)
     * .constructMapInvokeData()
     * .flush(response,"fileName");
     */
    public ExcelDirector constructMapInvokeData() {
        Assert.notNull(clazz, "buildInvokeClass(clazz) need to do ");
        Assert.notNull(methodParamJson, "buildInvokeMethodParamValue(methodParamJson , methodParamLimitStart,methodParamLimitSize) need to do");
        Assert.notNull(methodParamLimitStart, "buildInvokeMethodParamValue(methodParamJson , methodParamLimitStart,methodParamLimitSize) need to do");
        Assert.notNull(methodParamLimitSize, "buildInvokeMethodParamValue(methodParamJson , methodParamLimitStart,methodParamLimitSize) need to do");

        abstractExcelBuilder
                .buildWorkbook(workbook)
                .buildSheet(sheetName)
                .buildColumn(columnSize, isAutoColumnWidth)
                .buildStyle()
                .buildTitlesAndHeads(titles, heads)
                .buildInvokeClass(clazz)
                .buildInvokeMethodParamValue(methodParamJson, methodParamLimitStart, methodParamLimitSize)
                .buildContent(null, null, columnTypeMap, DefaultBuildContentInvokeData.class);
        return this;
    }

    /**
     * 添加屬性標題對照
     *
     * @param fieldTitle
     * @return
     */
    public ExcelDirector addFieldTitleTable(LinkedHashMap<String, String> fieldTitle) {
        if (fieldTitle == null || fieldTitle.size() == 0) {
            return null;
        }
        Set<String> strings = fieldTitle.keySet();
        for (String key : strings) {
            abstractExcelBuilder.addFieldTitleTable(key, fieldTitle.get(key));
        }
        setHeads(strings.toArray(new String[strings.size()]));
        return this;
    }

    public ExcelDirector addFieldTitleTable(String fieldName, String titleName) {
        abstractExcelBuilder.addFieldTitleTable(fieldName, titleName);
        return this;
    }


    public SXSSFWorkbook getWorkbook() {
        return abstractExcelBuilder.getWorkbook();
    }

    public ExcelDirector setWorkbook(SXSSFWorkbook workbook) {
        abstractExcelBuilder.workbook = workbook;
        return this;
    }

    /**
     * 覆蓋-獲取屬性值
     *
     * @param getFieldValue
     * @return
     */
    public ExcelDirector overrideDefaultGetFieldValue(AbstractGetFieldValue getFieldValue) {
        abstractExcelBuilder.getFieldValueImpl(getFieldValue);
        return this;
    }

    public ExcelDirector isAutoColumnWidth(boolean isAutoColumnWidth) {
        this.isAutoColumnWidth = isAutoColumnWidth;
        return this;
    }

    /**
     * 覆蓋-默認設置的樣式
     *
     * @param setStyle
     * @return
     */
    public ExcelDirector overrideDefaultSetStyle(AbstractBuildStyle setStyle) {
        abstractExcelBuilder.setStyleImpl(setStyle);
        return this;
    }

    /**
     * 覆蓋-默認設置標題
     *
     * @param setTitle
     * @return
     */
    public ExcelDirector overrideDefaultSetTitle(AbstractBuildTitle setTitle) {
        abstractExcelBuilder.setTitleImpl(setTitle);
        return this;
    }


    /**
     * 寫到響應流
     *
     * @param response
     */
    public void flush(HttpServletResponse response) {
        abstractExcelBuilder.flush(response);
    }

    public void flush(HttpServletResponse response, String excelFileName) {
        abstractExcelBuilder.flush(response, excelFileName);
    }

    public ExcelDirector setSheetName(String sheetName) {
        this.sheetName = sheetName;
        return this;
    }

    public ExcelDirector setHeads(String[] heads) {
        if (columnSize == null) {
            columnSize = heads.length;
        }
        this.heads = heads;
        return this;
    }

    public Collection getData() {
        return data;
    }

    public ExcelDirector setData(Collection data) {
        this.data = data;
        return this;
    }

    /**
     * 設置列對應數據類型
     *
     * @param columnTypeMap
     * @return
     */
    public ExcelDirector setColumnTypeMap(LinkedHashMap<String, Integer> columnTypeMap) {
        this.columnTypeMap = columnTypeMap;
        return this;
    }

    /**
     * 設置標題
     *
     * @param titles
     * @return
     */
    public ExcelDirector setTitles(String... titles) {
        this.titles = titles;
        return this;
    }

    /**
     * 設置文件名稱
     *
     * @param excelFileName
     * @return
     */
    public ExcelDirector setExcelFileName(String excelFileName) {
        this.excelFileName = excelFileName;
        return this;
    }


    /**
     * 設置反射類名
     *
     * @param invokeClass
     * @return
     */
    public ExcelDirector setBoundInvokeClass(Class invokeClass) {
        this.clazz = invokeClass;
        return this;
    }

    /**
     * 設置反射方法中參數值
     *
     * @param methodParamJson
     * @param methodParamLimitStart
     * @param methodParamLimitSize
     * @return
     * @see BaseSetContentInterface
     */
    public ExcelDirector setBoundInvokeMethodParamValues(String methodParamJson, Integer methodParamLimitStart, Integer methodParamLimitSize) {
        this.methodParamJson = methodParamJson;
        this.methodParamLimitStart = methodParamLimitStart;
        this.methodParamLimitSize = methodParamLimitSize;
        return this;
    }

}
  1. 使用示例
package com.mfz.study.util;

import com.alibaba.fastjson.JSONObject;
import com.mfz.study.util.build.BaseSetContentInterface;
import com.mfz.study.util.build.TestController;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description: 反射數據源實現
 * @Author mengfanzhu
 * @Date 2019/12/18 14:19
 * @Version 1.0
 */
@Service
public class InvokeDataSource implements BaseSetContentInterface {

    @Override
    public List<? extends Map<String, Object>> getExcelExportData(String json, Integer limitStart, Integer size) {
        TestController.ExcelExportModel param = JSONObject.parseObject(json,new TestController.ExcelExportModel().getClass());
        System.out.println(param.getAddress());
        System.out.println(param.getId());
        System.out.println(param.getName());
        //TODO do something ...  根據入參 獲取數據源

        if(limitStart >10){
            return new ArrayList<>();
        }
        List<HashMap<String, Object>> data = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            HashMap<String, Object> d = new HashMap<>();
            d.put("name", "黎明" + i);
            d.put("address", "北京朝陽" + i);
            d.put("id", "00001" + i);
            data.add(d);
        }
        return data;
    }
}
  1. 源碼地址  https://github.com/fzmeng/Excelbuild

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章