Java基础 (十一) | 上传、下载、导入、导出

Scroll Down

前言

hello,大家好,俗话说,上传下载是我们作为开发必不可少的业务,这里讲解比较常用的单纯上传下载功能,不涉及到很高级的比如幂等性、鉴权等业务

废话不多说,直接撸代码

一、上传

1. 接口

@RequestMapping(value = "/uploadFile.ajax", method = RequestMethod.POST)
    @ResponseBody
    public Result uploads(HttpServletRequest request, @RequestParam(required = true) MultipartFile file,
                          @ApiParam(value = "文件类型") @RequestParam(defaultValue = "1") Integer type) {
        try {
            if (file == null) {
                throw new ServiceException("上传文件不能为空");
            }
            // 文件名校验
            String fileName = file.getOriginalFilename();
            if (!fileName.matches(GenConstants.LOWEXCEL) && !fileName.matches(GenConstants.HIGHEXCEL)) {
                throw new ServiceException(ResultEnum.FILE_INCORRENT.getMessage());
            }
            // 文件大小校验
            if (!(file.getSize() / CommonConstant.FILE_FORMAT_SIZE / CommonConstant.FILE_FORMAT_SIZE < 10)) {
                throw new ServiceException("文件过大,不能超过10MB");
            }
            commonService.uploadFile(request, file, type);
        } catch (Exception e) {
            throw new ServiceException("上传失败,文件过大或格式有误");
        }
        return ResultGenerator.genSuccessResult("上传成功");
    }

多个文件的话直接数组接收参数再循环即可

2. 逻辑

public void uploadFile(HttpServletRequest request, MultipartFile file, Integer type) throws Exception {
        // 上传目录地址
        String uploadDir = request.getSession().getServletContext().getRealPath("/") + "upload/type" + type + "/";
        // 如果目录不存在,自动创建文件夹
        File dir = new File(uploadDir);
        if (!dir.exists()) {
            dir.mkdir();
        }
        // 调用上传方法
        HashMap<String, String> uploadInfo = executeUpload(uploadDir, file);
}

 public HashMap<String, String> executeUpload(String uploadDir, MultipartFile file) throws Exception {
        HashMap<String, String> upload = new HashMap<>();
        // 文件后缀名
        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        String name = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf("."));
        // 上传文件名
        String fileName = name + suffix;

        // 服务器端保存的文件对象
        File serverFile = new File(uploadDir + fileName);
        // 将上传的文件写入到服务器端文件内
        FileUtils.copyInputStreamToFile(file.getInputStream(), serverFile);
        long attachmentSize = file.getSize();

        FTPClientUtils ftp = FTPClientUtils.init();
        String contextPath = "qmp";
        String result = "上传至Ftp完成";
        boolean ret = ftp.put(contextPath + "/" + serverFile.getName(), serverFile.getAbsolutePath());

        if (ret) {
            String url = FTP_URL + "/" + contextPath + "/" + serverFile.getName();
            upload.put("fileName", fileName);
            upload.put("attachmentPath", url);
            upload.put("attachmentSize", String.valueOf(attachmentSize));
        } else {
            result = ", 上传至Ftp失败";
        }
        upload.put("result", result);
        return upload;
    }

FTPClientUtils 工具



import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.log4j.Logger;

/**
 * @author Terry FTP客户端
 * @creation 2017年8月18日-下午7:25:32
 */
public class FTPClientUtils {
	// ---------------------------------------------------------------------
	// Instance data
	// ---------------------------------------------------------------------
	/** logger */
	protected final Logger log = Logger.getLogger(getClass());
	private ThreadLocal<FTPClient> ftpClientThreadLocal = new ThreadLocal<FTPClient>();

	private String host;
	private int port;
	private String username;
	private String password;

	private boolean binaryTransfer = true;
	private boolean passiveMode = true;
	private String encoding = "UTF-8";
	private int clientTimeout = 1000 * 30;
	private int bufSize = 1024 * 1024 * 10;// 10M缓冲区10M

	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public boolean isBinaryTransfer() {
		return binaryTransfer;
	}

	public void setBinaryTransfer(boolean binaryTransfer) {
		this.binaryTransfer = binaryTransfer;
	}

	public boolean isPassiveMode() {
		return passiveMode;
	}

	public void setPassiveMode(boolean passiveMode) {
		this.passiveMode = passiveMode;
	}

	public String getEncoding() {
		return encoding;
	}

	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}

	public int getClientTimeout() {
		return clientTimeout;
	}

	public void setClientTimeout(int clientTimeout) {
		this.clientTimeout = clientTimeout;
	}

	// ---------------------------------------------------------------------
	// private method
	// ---------------------------------------------------------------------
	/**
	 * 返回一个FTPClient实例
	 * 
	 * @throws Exception
	 */
	private FTPClient getFTPClient() {
		if (ftpClientThreadLocal.get() != null && ftpClientThreadLocal.get().isConnected()) {
			return ftpClientThreadLocal.get();
		} else {
			FTPClient ftpClient = new FTPClient(); // 构造一个FtpClient实例
			ftpClient.setControlEncoding(encoding); // 设置字符集
			ftpClient.setBufferSize(bufSize);

			try {
				// 连接到ftp服务器
				connect(ftpClient);
			} catch (Exception e1) {
				e1.printStackTrace();
			}

			// 设置为passive模式
			if (passiveMode) {
				ftpClient.enterLocalPassiveMode();
			}
			try {
				// 设置文件传输类型
				setFileType(ftpClient);
			} catch (Exception e1) {
				e1.printStackTrace();
			}

			try {
				ftpClient.setSoTimeout(clientTimeout);
			} catch (SocketException e) {
				e.printStackTrace();
			}
			ftpClientThreadLocal.set(ftpClient);
			return ftpClient;
		}
	}

	/**
	 * 设置文件传输类型
	 * 
	 * @throws Exception
	 * @throws IOException
	 */
	private void setFileType(FTPClient ftpClient) throws Exception {
		try {
			if (binaryTransfer) {
				ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
			} else {
				ftpClient.setFileType(FTPClient.ASCII_FILE_TYPE);
			}
		} catch (IOException e) {
			throw new Exception("Could not to set file type.", e);
		}
	}

	/**
	 * 连接到ftp服务器
	 * 
	 * @param ftpClient
	 * @return 连接成功返回true,否则返回false
	 * @throws Exception
	 */
	private boolean connect(FTPClient ftpClient) throws Exception {
		try {
			ftpClient.connect(host, port);

			// 连接后检测返回码来校验连接是否成功
			int reply = ftpClient.getReplyCode();

			if (FTPReply.isPositiveCompletion(reply)) {
				// 登陆到ftp服务器
				if (ftpClient.login(username, password)) {
					setFileType(ftpClient);
					return true;
				}
			} else {
				ftpClient.disconnect();
				throw new Exception("FTP server refused connection.");
			}
		} catch (IOException e) {
			if (ftpClient.isConnected()) {
				try {
					ftpClient.disconnect(); // 断开连接
				} catch (IOException e1) {
					throw new Exception("Could not disconnect from server.", e1);
				}

			}
			throw new Exception("Could not connect to server.", e);
		}
		return false;
	}

	// ---------------------------------------------------------------------
	// public method
	// ---------------------------------------------------------------------
	/**
	 * 断开ftp连接
	 * 
	 * @throws Exception
	 */
	public void disconnect() throws Exception {
		try {
			FTPClient ftpClient = getFTPClient();
			ftpClient.logout();
			if (ftpClient.isConnected()) {
				ftpClient.disconnect();
				ftpClient = null;
			}
			log.info("连接关闭");
		} catch (IOException e) {
			throw new Exception("Could not disconnect from server.", e);
		}
	}

	public boolean mkdir(String pathname) throws Exception {
		return mkdir(pathname, null);
	}

	/**
	 * 在ftp服务器端创建目录(不支持一次创建多级目录)
	 * 
	 * 该方法执行完后将自动关闭当前连接
	 * 
	 * @param pathname
	 * @return
	 * @throws Exception
	 */
	public boolean mkdir(String pathname, String workingDirectory) throws Exception {
		return mkdir(pathname, workingDirectory, true);
	}

	/**
	 * 在ftp服务器端创建目录(不支持一次创建多级目录)
	 * 
	 * @param pathname
	 * @param autoClose
	 *            是否自动关闭当前连接
	 * @return
	 * @throws Exception
	 */
	public boolean mkdir(String pathname, String workingDirectory, boolean autoClose) throws Exception {
		try {
			getFTPClient().changeWorkingDirectory(workingDirectory);
			return getFTPClient().makeDirectory(pathname);
		} catch (IOException e) {
			throw new Exception("Could not mkdir.", e);
		} finally {
			if (autoClose) {
				disconnect(); // 断开连接
			}
		}
	}

	/**
	 * 上传一个本地文件到远程指定文件
	 * 
	 * @param remoteAbsoluteFile
	 *            远程文件名(包括完整路径)
	 * @param localAbsoluteFile
	 *            本地文件名(包括完整路径)
	 * @return 成功时,返回true,失败返回false
	 * @throws Exception
	 */
	public boolean put(String remoteAbsoluteFile, String localAbsoluteFile) throws Exception {
		return put(remoteAbsoluteFile, localAbsoluteFile, true);
	}

	/**
	 * 上传一个本地文件到远程指定文件
	 * 
	 * @param remoteAbsoluteFile
	 *            远程文件名(包括完整路径)
	 * @param localAbsoluteFile
	 *            本地文件名(包括完整路径)
	 * @param autoClose
	 *            是否自动关闭当前连接
	 * @return 成功时,返回true,失败返回false
	 * @throws Exception
	 */
	public boolean put(String remoteAbsoluteFile, String localAbsoluteFile, boolean autoClose) throws Exception {
		InputStream input = null;
		try {
			// 处理传输
			input = new FileInputStream(localAbsoluteFile);
			System.out.println("上传的文件为:" + localAbsoluteFile);
			getFTPClient().storeFile(remoteAbsoluteFile, input);
			log.debug("put " + localAbsoluteFile);
			return true;
		} catch (FileNotFoundException e) {
			throw new Exception("local file not found.", e);
		} catch (IOException e) {
			throw new Exception("Could not put file to server.", e);
		} finally {
			try {
				if (input != null) {
					input.close();
				}
			} catch (Exception e) {
				throw new Exception("Couldn't close FileInputStream.", e);
			}
			if (autoClose) {
				disconnect(); // 断开连接
			}
		}
	}
	/**
	 * 下载一个远程文件到本地的指定文件
	 * 
	 * @param remoteAbsoluteFile
	 *            远程文件名(包括完整路径)
	 * @param localAbsoluteFile
	 *            本地文件名(包括完整路径)
	 * @return 成功时,返回true,失败返回false
	 * @throws Exception
	 */
	public boolean get(String remoteAbsoluteFile, String localAbsoluteFile) throws Exception {
		return get(remoteAbsoluteFile, localAbsoluteFile, true);
	}

	/**
	 * 下载一个远程文件到本地的指定文件
	 * 
	 * @param remoteAbsoluteFile
	 *            远程文件名(包括完整路径)
	 * @param localAbsoluteFile
	 *            本地文件名(包括完整路径)
	 * @param autoClose
	 *            是否自动关闭当前连接
	 * 
	 * @return 成功时,返回true,失败返回false
	 * @throws Exception
	 */
	public boolean get(String remoteAbsoluteFile, String localAbsoluteFile, boolean autoClose) throws Exception {
		OutputStream output = null;
		try {
			output = new FileOutputStream(localAbsoluteFile);
			return get(remoteAbsoluteFile, output, autoClose);
		} catch (FileNotFoundException e) {
			throw new Exception("local file not found.", e);
		} finally {
			try {
				if (output != null) {
					output.close();
				}
			} catch (IOException e) {
				throw new Exception("Couldn't close FileOutputStream.", e);
			}
		}
	}

	/**
	 * 下载一个远程文件到指定的流 处理完后记得关闭流
	 * 
	 * @param remoteAbsoluteFile
	 * @param output
	 * @return
	 * @throws Exception
	 */
	public boolean get(String remoteAbsoluteFile, OutputStream output) throws Exception {
		return get(remoteAbsoluteFile, output, true);
	}

	/**
	 * 下载一个远程文件到指定的流 处理完后记得关闭流
	 * 
	 * @param remoteAbsoluteFile
	 * @param output
	 * @param delFile
	 * @return
	 * @throws Exception
	 */
	public boolean get(String remoteAbsoluteFile, OutputStream output, boolean autoClose) throws Exception {
		try {
			FTPClient ftpClient = getFTPClient();
			// 处理传输
			return ftpClient.retrieveFile(remoteAbsoluteFile, output);
		} catch (IOException e) {
			throw new Exception("Couldn't get file from server.", e);
		} finally {
			if (autoClose) {
				disconnect(); // 关闭链接
			}
		}
	}

	/**
	 * 从ftp服务器上删除一个文件 该方法将自动关闭当前连接
	 * 
	 * @param delFile
	 * @return
	 * @throws Exception
	 */
	public boolean delete(String delFile) throws Exception {
		return delete(delFile, true);
	}

	/**
	 * 从ftp服务器上删除一个文件
	 * 
	 * @param delFile
	 * @param autoClose
	 *            是否自动关闭当前连接
	 * 
	 * @return
	 * @throws Exception
	 */
	public boolean delete(String delFile, boolean autoClose) throws Exception {
		try {
			getFTPClient().deleteFile(delFile);
			return true;
		} catch (IOException e) {
			throw new Exception("Couldn't delete file from server.", e);
		} finally {
			if (autoClose) {
				disconnect(); // 关闭链接
			}
		}
	}

	/**
	 * 批量删除 该方法将自动关闭当前连接
	 * 
	 * @param delFiles
	 * @return
	 * @throws Exception
	 */
	public boolean delete(String[] delFiles) throws Exception {
		return delete(delFiles, true);
	}

	/**
	 * 批量删除
	 * 
	 * @param delFiles
	 * @param autoClose
	 *            是否自动关闭当前连接
	 * 
	 * @return
	 * @throws Exception
	 */
	public boolean delete(String[] delFiles, boolean autoClose) throws Exception {
		try {
			FTPClient ftpClient = getFTPClient();
			for (String s : delFiles) {
				ftpClient.deleteFile(s);
			}
			return true;
		} catch (IOException e) {
			throw new Exception("Couldn't delete file from server.", e);
		} finally {
			if (autoClose) {
				disconnect(); // 关闭链接
			}
		}
	}

	/**
	 * 列出远程默认目录下所有的文件
	 * 
	 * @return 远程默认目录下所有文件名的列表,目录不存在或者目录下没有文件时返回0长度的数组
	 * @throws Exception
	 */
	public String[] listNames() throws Exception {
		return listNames(null, true);
	}

	public String[] listNames(boolean autoClose) throws Exception {
		return listNames(null, autoClose);
	}

	/**
	 * 列出远程目录下所有的文件
	 * 
	 * @param remotePath
	 *            远程目录名
	 * @param autoClose
	 *            是否自动关闭当前连接
	 * 
	 * @return 远程目录下所有文件名的列表,目录不存在或者目录下没有文件时返回0长度的数组
	 * @throws Exception
	 */
	public String[] listNames(String remotePath, boolean autoClose) throws Exception {
		try {
			String[] listNames = getFTPClient().listNames(remotePath);
			return listNames;
		} catch (IOException e) {
			throw new Exception("列出远程目录下所有的文件时出现异常", e);
		} finally {
			if (autoClose) {
				disconnect(); // 关闭链接
			}
		}
	}

	public static FTPClientUtils init() {
		FTPClientUtils ftp = new FTPClientUtils();
		
		ftp.setHost("XXX");
		ftp.setPort(2121);
		ftp.setUsername("user");
		ftp.setPassword("pass");
		ftp.setBinaryTransfer(true);
		ftp.setPassiveMode(false);
		ftp.setEncoding("utf-8");
		return ftp;
	}

	public static void main(String[] args) throws Exception, InterruptedException {
		FTPClientUtils ftp = FTPClientUtils.init();
//		ftp.mkdir("TBD");
		System.out.print("开始上传...");
		File file = new File("F:/test/");
		for (File file2 : file.listFiles()) {
			boolean ret = ftp.put(file2.getName(), file2.getAbsolutePath());
			if (ret) {
				String result = "上传完成";
				System.out.println(file2.getName() + result);
			} else {
				String result = "上传失败";
				System.out.println(file2.getName() + result);
			}
		}
		System.out.println("上传全部完成");
	}
}

二、下载

下载一般用在下载模板、下载固定文件,其实有好几种方案,这里一个个说

  • 前端使用url下载
    使用windows下载

  • 前端js下载
    这里就不讲这一个了,随便百度找下即可

– 下载静态文件

<el-link type="primary" target="_blank" :href="`${path}static/template/${tempName}`">
   点击下载
</el-link>
data() {
    return {
      path: process.env.BASE_URL
    }
},
  • 后端下载
 @PostMapping("/downTemplate.ajax")
    @ApiOperation("下载模板")
    public void exportItemCheck(HttpServletResponse response) {
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        response.setCharacterEncoding("utf-8");
       try {
            String filename = CustomFieldEnum.getByType(type).getName() + "模板.xls";
            filename = new String(filename.getBytes("gb2312"), "ISO8859-1");
            response.setHeader("Content-disposition", "attachment;filename=" + filename);
            // 表头
            HashMap<String, String> headers = new LinkedHashMap<>();
            getExpostHeader(headers, type, true);
            ExcelUtil.exportExcel(headers, new ArrayList<>(), response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
 }
    
 protected void getExpostHeader(Map<String, String> headers, Integer type,Boolean flagCreate){
        CustomFieldReq customFieldReq = new CustomFieldReq ();
        customFieldReq.setUserName(CookieUtils.getCurrentUser());
        customFieldReq.setType(type);
        List<DTO> dtos = 查询
        for (DTO dto:dtos){
        	headers.put(req.getFieldKey(), fieldName);
        }
    }   

ExcelUtil 工具

package com.qa.test.system.util.excelutil;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.ComparatorUtils;
import org.apache.commons.collections.comparators.ComparableComparator;
import org.apache.commons.collections.comparators.ComparatorChain;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.common.usermodel.HyperlinkType;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.reflect.Field;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * The <code>ExcelUtil</code> 与 {@link ExcelCell}搭配使用
 *
 * @author sargeras.wang
 * @version 1.0, Created at 2013年9月14日
 */
public class ExcelUtil {

    private static Logger LG = LoggerFactory.getLogger(ExcelUtil.class);

    /**
     * 用来验证excel与Vo中的类型是否一致 <br>
     * Map<栏位类型,只能是哪些Cell类型>
     */
    private static Map<Class<?>, CellType[]> validateMap = new HashMap<>();

    static {
        validateMap.put(String[].class, new CellType[]{CellType.STRING});
        validateMap.put(Double[].class, new CellType[]{CellType.NUMERIC});
        validateMap.put(String.class, new CellType[]{CellType.STRING});
        validateMap.put(Double.class, new CellType[]{CellType.NUMERIC});
        validateMap.put(Date.class, new CellType[]{CellType.NUMERIC, CellType.STRING});
        validateMap.put(Integer.class, new CellType[]{CellType.NUMERIC});
        validateMap.put(Float.class, new CellType[]{CellType.NUMERIC});
        validateMap.put(Long.class, new CellType[]{CellType.NUMERIC});
        validateMap.put(Boolean.class, new CellType[]{CellType.BOOLEAN});
    }

    /**
     * 获取cell类型的文字描述
     *
     * @param cellType <pre>
     *                 CellType.BLANK
     *                 CellType.BOOLEAN
     *                 CellType.ERROR
     *                 CellType.FORMULA
     *                 CellType.NUMERIC
     *                 CellType.STRING
     *                 </pre>
     * @return
     */
    private static String getCellTypeByInt(CellType cellType) {
        if(cellType == CellType.BLANK)
            return "Null type";
        else if(cellType == CellType.BOOLEAN)
            return "Boolean type";
        else if(cellType == CellType.ERROR)
            return "Error type";
        else if(cellType == CellType.FORMULA)
            return "Formula type";
        else if(cellType == CellType.NUMERIC)
            return "Numeric type";
        else if(cellType == CellType.STRING)
            return "String type";
        else
            return "Unknown type";
    }

    /**
     * 获取单元格值
     *
     * @param cell
     * @return
     */
    public static String getCellValue(Cell cell) {

        if (cell == null
                || (cell.getCellTypeEnum() == CellType.STRING && StringUtils.isBlank(cell
                .getStringCellValue()))) {
            return null;
        }
        CellType cellType = cell.getCellTypeEnum();
        if(cellType == CellType.BLANK)
            return null;
        else if(cellType == CellType.BOOLEAN)
            return String.valueOf(cell.getBooleanCellValue());
        else if(cellType == CellType.ERROR)
            return String.valueOf(cell.getErrorCellValue());
        else if(cellType == CellType.FORMULA) {
            try {
                if (HSSFDateUtil.isCellDateFormatted(cell)) {
                    return String.valueOf(cell.getDateCellValue());
                } else {
                    return String.valueOf(cell.getNumericCellValue());
                }
            } catch (IllegalStateException e) {
                return String.valueOf(cell.getRichStringCellValue());
            }
        }
        else if(cellType == CellType.NUMERIC){
            if (DateUtil.isCellDateFormatted(cell)) {
                return String.valueOf(cell.getDateCellValue());
            } else {
                return String.valueOf(cell.getNumericCellValue());
            }
        }
        else if(cellType == CellType.STRING)
            return cell.getStringCellValue();
        else
            return null;
    }

    /**
     * 利用JAVA的反射机制,将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出到指定IO设备上<br>
     * 用于单个sheet
     *
     * @param <T>
     * @param headers 表格属性列名数组
     * @param dataset 需要显示的数据集合,集合中一定要放置符合javabean风格的类的对象。此方法支持的
     *                javabean属性的数据类型有基本数据类型及String,Date,String[],Double[]
     * @param out     与输出设备关联的流对象,可以将EXCEL文档导出到本地文件或者网络中
     */
    public static <T> void exportExcel(Map<String,String> headers, Collection<T> dataset, OutputStream out) {
        exportExcel(headers, dataset, out, null);
    }

    /**
     * 利用JAVA的反射机制,将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出到指定IO设备上<br>
     * 用于单个sheet
     *
     * @param <T>
     * @param headers 表格属性列名数组
     * @param dataset 需要显示的数据集合,集合中一定要放置符合javabean风格的类的对象。此方法支持的
     *                javabean属性的数据类型有基本数据类型及String,Date,String[],Double[]
     * @param out     与输出设备关联的流对象,可以将EXCEL文档导出到本地文件或者网络中
     * @param pattern 如果有时间数据,设定输出格式。默认为"yyy-MM-dd"
     */
    @SuppressWarnings("resource")
    public static <T> void exportExcel(Map<String,String> headers, Collection<T> dataset, OutputStream out,
                                       String pattern) {
        // 声明一个工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 生成一个表格
        HSSFSheet sheet = workbook.createSheet();

        write2Sheet(sheet, headers, dataset, pattern,workbook);
        try {
            workbook.write(out);
        } catch (IOException e) {
            LG.error(e.toString(), e);
        }
    }

    public static List<Map<String,String>> getProjectKeyParamList(Workbook wb ,int colNum) {

        Sheet sheet = null;
        Row row = null;

        String cellData = null;

        //用来存放表中数据
        List <Map<String,String>> list = new ArrayList<Map<String,String>>();

        if(wb != null){

            //获取第一个sheet
            sheet = wb.getSheetAt(0);

            int startRow =0;
            if(sheet.getMergedRegion(0) != null){
                //表头占得行数
                startRow =sheet.getMergedRegion(0).getLastRow();
            }

            //效验表头模板
            CellRangeAddress ca = sheet.getMergedRegion(0);
            int heardMaxRow = 0;
            if(ca != null){
                heardMaxRow = ca.getLastRow();
            }

            //获取最大行数
            int rowNum = sheet.getPhysicalNumberOfRows();
            //获取第一行
            row = sheet.getRow(0);
            //获取最大列数
           // int colNum = row.getLastCellNum();

            //key是所在的行列,value是单元格的值
            Map<String,String> map = null;
            for (int i = 0; i < rowNum; i++) {

                map = new LinkedHashMap<String,String>();
                row = sheet.getRow(i);
                if(row != null ){

                    //从第0列开始
                    for(int j = 0; j < (colNum+1); j++){
                        cellData = (String) getCellValue(row.getCell(j));

                        if(cellData==null || "".equals(cellData)){
                            continue;
                        }
                        map.put(i+"-"+j,cellData);
                    }

                }
                list.add(map);
            }
        }

        return  list;
    }

    @SuppressWarnings("resource")
    public static void exportExcel(String[][] datalist, OutputStream out) {
        try {
            // 声明一个工作薄
            HSSFWorkbook workbook = new HSSFWorkbook();
            // 生成一个表格
            HSSFSheet sheet = workbook.createSheet();

            for (int i = 0; i < datalist.length; i++) {
                String[] r = datalist[i];
                HSSFRow row = sheet.createRow(i);
                for (int j = 0; j < r.length; j++) {
                    HSSFCell cell = row.createCell(j);
                    //cell max length 32767
                    if (r[j].length() > 32767) {
                        r[j] = "--此字段过长(超过32767),已被截断--" + r[j];
                        r[j] = r[j].substring(0, 32766);
                    }
                    cell.setCellValue(r[j]);
                }
            }
            //自动列宽
            if (datalist.length > 0) {
                int colcount = datalist[0].length;
                for (int i = 0; i < colcount; i++) {
                    sheet.autoSizeColumn(i);
                }
            }
            workbook.write(out);
        } catch (IOException e) {
            LG.error(e.toString(), e);
        }
    }

    /**
     * 利用JAVA的反射机制,将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出到指定IO设备上<br>
     * 用于多个sheet
     *
     * @param <T>
     * @param sheets {@link ExcelSheet}的集合
     * @param out    与输出设备关联的流对象,可以将EXCEL文档导出到本地文件或者网络中
     */
    public static <T> void exportExcel(List<ExcelSheet<T>> sheets, OutputStream out) {
        exportExcel(sheets, out, null);
    }

    /**
     * 利用JAVA的反射机制,将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出到指定IO设备上<br>
     * 用于多个sheet
     *
     * @param <T>
     * @param sheets  {@link ExcelSheet}的集合
     * @param out     与输出设备关联的流对象,可以将EXCEL文档导出到本地文件或者网络中
     * @param pattern 如果有时间数据,设定输出格式。默认为"yyy-MM-dd"
     */
    @SuppressWarnings("resource")
    public static <T> void exportExcel(List<ExcelSheet<T>> sheets, OutputStream out, String pattern) {
        if (CollectionUtils.isEmpty(sheets)) {
            return;
        }
        // 声明一个工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        for (ExcelSheet<T> sheet : sheets) {
            // 生成一个表格
            HSSFSheet hssfSheet = workbook.createSheet(sheet.getSheetName());
            write2Sheet(hssfSheet, sheet.getHeaders(), sheet.getDataset(), pattern,workbook);
        }
        try {
            workbook.write(out);
        } catch (IOException e) {
            LG.error(e.toString(), e);
        }
    }

    public static <T> void writeKeyParamTemplate(Map<String,Object> headers,  List<HashMap<String,String>> data, OutputStream out) {

        // 声明一个工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 生成一个表格
        HSSFSheet sheet = workbook.createSheet();

        // 产生表格标题行
        HSSFRow row = sheet.createRow(0);


        LinkedHashSet<String> headerIDList = getHeadData(headers, workbook, sheet, row);

        sheet.setDefaultRowHeight((short)300.0);
        sheet.setDefaultColumnWidth(20);
        try {
            workbook.write(out);
            out.flush();
            out.close();
        } catch (IOException e) {
            LG.error(e.toString(), e);
        }

    }
    public static <T> void writeKeyParamExcel(Map<String,Object> headers,  List<HashMap<String,String>> data, OutputStream out) {

        // 声明一个工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 生成一个表格
        HSSFSheet sheet = workbook.createSheet();

        // 产生表格标题行
        HSSFRow row = sheet.createRow(0);


        LinkedHashSet<String> headerIDList = getHeadData(headers, workbook, sheet, row);
        int c;
        HSSFRichTextString text;
        HSSFCell cell;

        c = 1;
        //打印表格中的数据
        if(headerIDList != null && !headerIDList.isEmpty()){

            int rowNum  = sheet.getLastRowNum();

            for(HashMap<String,String> keyValue : data){
                rowNum++;
                row = sheet.createRow(rowNum);
                c = 0;

                //打印机型
                if(keyValue.get("projectModel")!=null){
                    text = new HSSFRichTextString(keyValue.get("projectModel"));
                    cell = row.createCell(c);
                    cell.setCellValue(text);
                    c++;
                }

                if(keyValue.get("keyParam")==null){
                    continue;
                }
                //打印中间动态的数据
                String[] rowObject = keyValue.get("keyParam").split(",");

                for (String id :headerIDList) {
                    int flag =0 ;
                   for(String cellObject : rowObject){

                       String[] cellValue = cellObject.split(";");
                       if(cellValue[0].equals(id)){
                           flag =1;
                           text = new HSSFRichTextString(cellValue[1]);
                           cell = row.createCell(c);
                           cell.setCellValue(text);
                           c++;
                           break;
                       }
                   }
                   if(flag ==0){
                       cell = row.createCell(c);
                       cell.setCellValue("");
                       c++;
                   }
                }
                //打印后两列
                if(keyValue.get("creator")!=null){
                    text = new HSSFRichTextString(keyValue.get("creator"));
                    cell = row.createCell(c);
                    cell.setCellValue(text);
                    c++;
                }
                if(keyValue.get("gmtCreate")!=null){
                    text = new HSSFRichTextString(keyValue.get("gmtCreate"));
                    cell = row.createCell(c);
                    cell.setCellValue(text);
                    c++;
                }

            }

        }

        sheet.setDefaultRowHeight((short)300.0);
        sheet.setDefaultColumnWidth(20);
        try {
            workbook.write(out);
            out.flush();
            out.close();
        } catch (IOException e) {
            LG.error(e.toString(), e);
        }
    }

    private static LinkedHashSet<String> getHeadData(Map<String, Object> headers, HSSFWorkbook workbook, HSSFSheet sheet, HSSFRow row) {
        HSSFFont titleFont = workbook.createFont();

        titleFont.setFontHeightInPoints((short) 14);
        CellStyle titleStyle = workbook.createCellStyle();
        titleStyle.setFont(titleFont);

        titleStyle.setAlignment(HorizontalAlignment.CENTER);

        // 标题行转中文
        Set<String> keys = headers.keySet();

        Iterator<String> it1 = keys.iterator();
        String key = "";    //存放临时键变量
        int c = 0;   //标题列数

        LinkedHashSet<String> headerIDList =  new LinkedHashSet<>();

        HSSFCell cell = null;
        HSSFRichTextString text = null;

        while (it1.hasNext()) {
            key = it1.next();

            //打印表头
            if("array".equals(key)){
                JSONArray array = (JSONArray) headers.get(key);
                c = setKeyParamCellValue(0,c,row, cell, array,sheet,titleStyle,headerIDList);

            }else {
                text = new HSSFRichTextString(headers.get(key).toString());
                cell = row.createCell(c);
                cell.setCellValue(text);
                cell.setCellStyle(titleStyle);
                c++;
            }
        }

        int startCol = 1;
        int overCol =  1;

        //合并表头单元格
        JSONArray array = (JSONArray) headers.get("array");
        mergedKeyParamCellValue(startCol,overCol,array,sheet);
        return headerIDList;
    }

    private static void mergedKeyParamCellValue( int startCol,int overCol, JSONArray array,HSSFSheet sheet ) {

        int maxColumn = 0;
        for(int i=0;i<=sheet.getLastRowNum();i++){
            int size = sheet.getRow(i).getLastCellNum();
            if(size>maxColumn){
                maxColumn=size;
            }
        }
        //合并列
        HashMap<Integer,Integer> map = new HashMap<>();
        //合并行
        for(int i = 0; i< maxColumn; i++) {
            int startRow=0;
            for(int j = 1; j<  sheet.getLastRowNum()+1; j++){
                Object cellValue = sheet.getRow(j).getCell(i);
                if(cellValue != null && !"".equals(cellValue) || j==(sheet.getLastRowNum())){
                    if(cellValue == null){
                        if((j) > startRow) {
                            sheet.addMergedRegion(new CellRangeAddress(startRow, j, i,i));
                            map.put(i,j);
                        }
                    }
                    startRow = j;
                }
            }
        }
        for(int i = 0; i<= sheet.getLastRowNum(); i++) {
            for(int j = 1; j<  maxColumn-1; j++){
                Object cellValue = sheet.getRow(i).getCell(j);
                if(cellValue != null && !"".equals(cellValue) || j==(maxColumn)){
                    if((j-1) > startCol) {
                        if(map.containsKey(j-1)){
                            int val = map.get(j-1);
                            if(i==val){
                                startCol = j;
                            }else{
                                if((j-1) > startCol  && cellValue == null) {
                                    sheet.addMergedRegion(new CellRangeAddress(i, i, startCol, j -1));
                                }
                                else{
                                    startCol = j;
                                }
                            }
                        }else{
                            if((j-1) > startCol && cellValue == null) {
                                sheet.addMergedRegion(new CellRangeAddress(i, i, startCol, j -1));
                            } else{
                                startCol = j;
                            }
                        }
                    }
                    startCol = j;
                }
            }
        }
    }


    private static int setKeyParamCellValue(int rowNum,int c,HSSFRow row, HSSFCell cell, JSONArray array,HSSFSheet sheet,CellStyle titleStyle,LinkedHashSet<String> headerIDList ) {

        HSSFRow rowTmp = sheet.getRow(rowNum);
        if(rowTmp != null){
            row = rowTmp;
        }
        else{
            row = sheet.createRow(rowNum);
        }
        rowNum  ++ ;

        HSSFRichTextString text;

        for(int i = 0; i< array.size(); i++){

            JSONObject json = (JSONObject)array.get(i);

            String fieldName = json.get("fieldName").toString();
            text = new HSSFRichTextString(fieldName);
            cell = row.createCell(c);
            cell.setCellValue(text);
            cell.setCellStyle(titleStyle);

            JSONArray sendArray = (JSONArray)json.get("children");
            if(sendArray == null){
                headerIDList.add(json.get("id").toString());
                c ++;
                continue;
            }
            c = setKeyParamCellValue( rowNum,c,row,cell,sendArray,sheet,titleStyle,headerIDList);
        }

        return c;
    }

    public static <T> void writeProjectItemExcel(String projectModel,Map<String,String> headers, List<LinkedHashSet<JSONObject>> itemTotalList,
                                                 OutputStream out,Map<String,String> allResultHeaders,JSONArray allResultArray,String categoryID) throws FileNotFoundException {

        // 声明一个工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 生成一个表格
        HSSFSheet sheet = workbook.createSheet(projectModel+"总检点结果");
        write2Sheet(sheet, allResultHeaders, allResultArray, null,workbook);
        String label = "";
        for (LinkedHashSet<JSONObject> results : itemTotalList) {
            for(JSONObject result : results){
                label = String.valueOf(result.get("label"));
            }
            sheet = workbook.createSheet(label +"阶段检点结果");
            //生成sheet内容
            if(Objects.equals(CategoryEnum.Europe.getType(),Integer.valueOf(categoryID))){
                getSheet(headers, results, 1, workbook, sheet);
            }else{
                getSheetCheckResult(headers, results, 1, workbook, sheet);
            }
        }

        sheet.setDefaultRowHeight((short)300.0);
        sheet.setDefaultColumnWidth(30);

        try {
            workbook.write(out);
            out.flush();
            out.close();
        } catch (IOException e) {
            LG.error(e.toString(), e);
        }

    }

    public static <T> void writeProjectItemCheckResultExcel(Map<String,String> headers, LinkedHashSet<JSONObject> results, OutputStream out) throws Exception {
        // 声明一个工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFSheet sheet = workbook.createSheet("检点结果");
        getSheetCheckResult(headers, results, 1, workbook, sheet);
        sheet.setDefaultRowHeight((short)300.0);
        sheet.setDefaultColumnWidth(30);

        try {
            workbook.write(out);
            out.flush();
            out.close();
        } catch (IOException e) {
            LG.error(e.toString(), e);
        }
    }


    public static <T> void getExportNetQualityTargetDetail(Map<String, String> headers,
        List<NetQualityTargetDetailReq> templateReqList, OutputStream out) {

        try {
            // 声明一个工作薄
            HSSFWorkbook workbook = new HSSFWorkbook();
            // 生成一个表格
            HSSFSheet sheet = workbook.createSheet("质量目标");
            HSSFFont titleFont = workbook.createFont();

            titleFont.setFontHeightInPoints((short)14);
            CellStyle titleStyle = workbook.createCellStyle();
            titleStyle.setFont(titleFont);

            titleStyle.setAlignment(HorizontalAlignment.CENTER);

            // 产生表格标题行
            HSSFRow row = sheet.createRow(0);
            // 标题行转中文
            Set<String> keys = headers.keySet();
            Iterator<String> it1 = keys.iterator();
            String key = ""; // 存放临时键变量
            int c = 0; // 标题列数
            while (it1.hasNext()) {
                key = it1.next();
                if (headers.containsKey(key)) {
                    HSSFCell cell = row.createCell(c);
                    cell.setCellStyle(titleStyle);
                    HSSFRichTextString text = new HSSFRichTextString(headers.get(key));
                    cell.setCellValue(text);
                    c++;
                }
            }

            HSSFCellStyle linkStyle = workbook.createCellStyle();
            HSSFFont linkFont = workbook.createFont();
            linkFont.setUnderline(HSSFFont.U_SINGLE);
            linkFont.setColor(HSSFColor.HSSFColorPredefined.BLUE.getIndex());
            linkStyle.setFont(linkFont);

            titleFont.setFontHeightInPoints((short)10);
            titleStyle = workbook.createCellStyle();
            titleStyle.setFont(titleFont);
            titleStyle.setAlignment(HorizontalAlignment.CENTER);

            HSSFCellStyle rowStyle = workbook.createCellStyle();
            // 遍历集合数据,产生数据行
            Iterator<NetQualityTargetDetailReq> it = templateReqList.iterator();
            HSSFCell cell = null;

            int index = 0;
            while (it.hasNext()) {
                index++;
                row = sheet.createRow(index);
                NetQualityTargetDetailReq t = it.next();
                try {

                    int cellNum = 0;
                    // 遍历列名
                    Iterator<String> it2 = keys.iterator();
                    while (it2.hasNext()) {
                        key = it2.next();
                        if (!headers.containsKey(key)) {
                            continue;
                        }
                        Object value = null;
                        if (QualityTemplateEnum.YEAR.getName().equals(key)) {
                            value = t.getYear().getLevelValue();
                        } else if (QualityTemplateEnum.FIRST.getName().equals(key)) {
                            value = t.getFirstLevel().getLevelValue();
                            if(StringUtils.isNotEmpty(String.valueOf(value))){
                                value = String.valueOf(value).split("_")[0];
                            }
                        } else if (QualityTemplateEnum.SECOND.getName().equals(key)) {
                            value = t.getSecondLevel().getLevelValue();
                            if(StringUtils.isNotEmpty(String.valueOf(value))){
                                value = String.valueOf(value).split("_")[0];
                            }
                        } else if (QualityTemplateEnum.THIRD.getName().equals(key)) {
                            value = t.getThirdLevel().getLevelValue();
                            if(StringUtils.isNotEmpty(String.valueOf(value))){
                                value = String.valueOf(value).split("_")[0];
                            }
                        } else if (QualityTemplateEnum.FOURTH.getName().equals(key)) {
                            value = t.getFourthLevel().getLevelValue();
                            if(StringUtils.isNotEmpty(String.valueOf(value))){
                                value = String.valueOf(value).split("_")[0];
                            }
                        } else if (QualityTemplateEnum.FIFTH.getName().equals(key)) {
                            value = t.getFifthLevel().getLevelValue();
                            if(StringUtils.isNotEmpty(String.valueOf(value))){
                                value = String.valueOf(value).split("_")[0];
                            }
                        } else if (QualityTemplateEnum.SIXTH.getName().equals(key)) {
                            value = t.getSixthLevel().getLevelValue();
                            if(StringUtils.isNotEmpty(String.valueOf(value))){
                                value = String.valueOf(value).split("_")[0];
                            }
                        } else if (QualityTemplateEnum.SEVENTH.getName().equals(key)) {
                            value = t.getSeventhLevel().getLevelValue();
                            if(StringUtils.isNotEmpty(String.valueOf(value))){
                                value = String.valueOf(value).split("_")[0];
                            }
                        } else if (QualityTemplateEnum.EIGHTH.getName().equals(key)) {
                            value = t.getEighthLevel().getLevelValue();
                            if(StringUtils.isNotEmpty(String.valueOf(value))){
                                value = String.valueOf(value).split("_")[0];
                            }
                        } else if (QualityTemplateEnum.PROJECT_NAME.getName().equals(key)) {
                            value = t.getProject().get("projectName");
                        } else if (QualityTemplateEnum.YEAR_TARGET_VALUE.getName().equals(key)) {
                            value = t.getYearTargetValue();
                        } else if (QualityTemplateEnum.Q1_TARGET_VALUE.getName().equals(key)) {
                            value = t.getQ1TargetValue();
                        } else if (QualityTemplateEnum.Q2_TARGET_VALUE.getName().equals(key)) {
                            value = t.getQ2TargetValue();
                        } else if (QualityTemplateEnum.Q3_TARGET_VALUE.getName().equals(key)) {
                            value = t.getQ3TargetValue();
                        } else if (QualityTemplateEnum.Q4_TARGET_VALUE.getName().equals(key)) {
                            value = t.getQ4TargetValue();
                        }

                        cell = row.createCell(cellNum);
                        cell.setCellStyle(titleStyle);
                        cellNum = setCellValue(cell, value, null, cellNum, null, row);
                        cellNum++;
                    }

                } catch (Exception e) {
                    LG.error(e.toString(), e);
                }
            }

            Iterator<String> it2 = keys.iterator();
            index = 0;
            while (it2.hasNext()) {
                key = it2.next();

                if (!headers.containsKey(key)) {
                    continue;
                }

                if (QualityTemplateEnum.YEAR.getName().equals(key)
                ||QualityTemplateEnum.PROJECT_NAME.getName().equals(key)
                ||QualityTemplateEnum.FIRST.getName().equals(key)
                ||QualityTemplateEnum.SECOND.getName().equals(key)
                ||QualityTemplateEnum.THIRD.getName().equals(key)
                ||QualityTemplateEnum.FOURTH.getName().equals(key)
                ||QualityTemplateEnum.FIFTH.getName().equals(key)
                ||QualityTemplateEnum.SIXTH.getName().equals(key)
                ||QualityTemplateEnum.SEVENTH.getName().equals(key)
                ) {
                   mergeSpecifiedColumn(sheet,index,rowStyle);
                }
                index++;
            }

            sheet.setDefaultColumnWidth(30);
            try {
                workbook.write(out);
                out.flush();
                out.close();
            } catch (IOException e) {
                LG.error(e.toString(), e);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static void mergeSpecifiedColumn(HSSFSheet sheet, int column,HSSFCellStyle titleStyle) {
        int totalRows = sheet.getLastRowNum(), firstRow = 0, lastRow = 0;

        boolean isLastCompareSame = false;//上一次比较是否相同

        //这里第一行是表头,从第三行开始判断是否相同
        if (totalRows >= 2) {
            for (int i = 2; i <= totalRows; i++) {
                String lastRowCellContent = sheet.getRow(i - 1).getCell(column).getStringCellValue();

                String curRowCellContent = sheet.getRow(i).getCell(column).getStringCellValue();

                if(StringUtils.isEmpty(lastRowCellContent)&& StringUtils.isEmpty(curRowCellContent)){
                    continue;
                }
                if (curRowCellContent.equals(lastRowCellContent)) {
                    if (!isLastCompareSame) {
                        firstRow = i - 1;

                    }

                    lastRow = i;

                    isLastCompareSame = true;

                } else {
                    isLastCompareSame = false;

                    if (lastRow > firstRow) {
                       // sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, column, column));

                    }
                }
                //最后一行时判断是否有需要合并的行
                if ((i == totalRows) && (lastRow > firstRow)) {
                    sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, column, column));

                    titleStyle.setAlignment(HorizontalAlignment.CENTER);
                    titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
                    sheet.getRow(firstRow).getCell(column).setCellStyle(titleStyle);
                }
            }
        }

    }
    
    private static void getSheetCheckResult(Map<String, String> headers, LinkedHashSet<JSONObject> array,
                                            int flag, HSSFWorkbook workbook, HSSFSheet sheet){

        // 产生表格标题行
        HSSFRow row = sheet.createRow(0);

        // 标题行转中文
        Set<String> keys = headers.keySet();

        Iterator<String> it1 = keys.iterator();
        String key = "";    //存放临时键变量
        int c= 0;   //标题列数
        while (it1.hasNext()){
            key = it1.next();
            if (headers.containsKey(key)) {
                HSSFCell cell = row.createCell(c);
                HSSFRichTextString text = new HSSFRichTextString(headers.get(key));
                cell.setCellValue(text);
                c++;
            }
        }


        // 遍历集合数据,产生数据行
        int index = 0;

        for(JSONObject jsonObject :array){

            String label = String.valueOf(jsonObject.get("label"));

            index++;
            row = sheet.createRow(index);

            int cellNum = 0;

            //阶段
            HSSFCell cell = row.createCell(cellNum);
            cellNum = setCellValue(cell,label,null,cellNum,null,row);

            cellNum++;

            //获取阶段下的部门列表
            LinkedHashSet<JSONObject> it2 =(LinkedHashSet<JSONObject>)jsonObject.get("children");
            if(it2 == null || it2.isEmpty()){
                return ;
            }
            int departmentIndex =0;
            //往excel里写值
            for (JSONObject department : it2){

                //获取部门
                label = String.valueOf(department.get("label"));
                cell = row.createCell(cellNum);

                cellNum = setCellValue(cell,label,null,cellNum,null,row);

                cellNum++;

                LinkedHashSet<JSONObject> centerList = (LinkedHashSet<JSONObject>)department.get("children");

                if(centerList==null || centerList.isEmpty()){
                    index++;
                    cellNum = cellNum -1;
                    //row = sheet.createRow(index);

                    continue;
                }
                int centerIndex =0;
                for (JSONObject center : centerList){

                    //获取中心
                    label = String.valueOf(center.get("label"));
                    cell = row.createCell(cellNum);

                    LinkedHashSet<JSONObject> groupList = (LinkedHashSet<JSONObject>)center.get("children");

                    cellNum = setCellValue(cell,label,null,cellNum,null,row);

                    cellNum++;

                    if(groupList==null || groupList.isEmpty()){
                        index++;
                        cellNum = cellNum -1;
                        row = sheet.createRow(index);

                        continue;
                    }
                    int groupIndex =0;
                    for (JSONObject group : groupList){

                        //获取小组
                        label = String.valueOf(group.get("label"));
                        cell = row.createCell(cellNum);

                        cellNum = setCellValue(cell,label,null,cellNum,null,row);

                        cellNum++;

                        LinkedHashSet<JSONObject> itemList = (LinkedHashSet<JSONObject>)group.get("children");

                        if(itemList==null || itemList.isEmpty()){
                            index++;
                            cellNum = cellNum -1;
                            row = sheet.createRow(index);

                            continue;
                        }
                        int itemIndex =0;
                        for (JSONObject item : itemList){

                            //点检项次
                            label = String.valueOf(item.get("label"));
                            cell = row.createCell(cellNum);
                            cellNum = setCellValue(cell,label,null,cellNum,null,row);
                            cellNum++;

                            //点检结果
                            label = String.valueOf(item.get("result"));
                            cell = row.createCell(cellNum);
                            cellNum = setCellValue(cell,label,null,cellNum,null,row);
                            cellNum++;

                            //点检人
                            label = String.valueOf(item.get("responMan"));
                            cell = row.createCell(cellNum);
                            cellNum = setCellValue(cell,label,null,cellNum,null,row);
                            cellNum++;

                            //附件
                            label = String.valueOf(item.get("attachmentName"));
                            cell = row.createCell(cellNum);
                            cellNum = setCellValue(cell,label,null,cellNum,null,row);
                            cellNum++;

                            //备注
                            label = String.valueOf(item.get("resultComment"));
                            cell = row.createCell(cellNum);
                            cellNum = setCellValue(cell,label,null,cellNum,null,row);
                            cellNum++;

                            LinkedHashSet<JSONObject> midList = (LinkedHashSet<JSONObject>)item.get("children");
                            if(midList == null || midList.isEmpty()){
                                index++;
                                cellNum = cellNum -1;
                                row = sheet.createRow(index);

                                continue;
                            }

                            int midIndex = 0;
                            for(JSONObject mid : midList){
                                //不合格问题及跟进
                                label = String.valueOf(mid.get("problemFollow"));
                                cell = row.createCell(cellNum);
                                cellNum = setCellValue(cell,label,null,cellNum,null,row);
                                cellNum++;

                                LinkedHashSet<JSONObject> detailList = (LinkedHashSet<JSONObject>)mid.get("children");
                                if(detailList == null || detailList.isEmpty()){
                                    index++;
                                    cellNum = cellNum -1;
                                    row = sheet.createRow(index);

                                    continue;
                                }

                                int detailIndex = 0;
                                for(JSONObject detail : detailList){
                                    //对应BUG/问题/风险链接
                                    label = String.valueOf(detail.get("originProblemDesc"));
                                    cell = row.createCell(cellNum);
                                    cellNum = setCellValue(cell,label,null,cellNum,null,row);
                                    cellNum++;

                                    //处理人
                                    label = String.valueOf(detail.get("handlerName"));
                                    cell = row.createCell(cellNum);
                                    cellNum = setCellValue(cell,label,null,cellNum,null,row);
                                    cellNum++;

                                    //测试工程师
                                    label = String.valueOf(detail.get("engineerName"));
                                    cell = row.createCell(cellNum);
                                    cellNum = setCellValue(cell,label,null,cellNum,null,row);
                                    cellNum++;

                                    //状态
                                    label = String.valueOf(detail.get("status"));
                                    cell = row.createCell(cellNum);
                                    cellNum = setCellValue(cell,label,null,cellNum,null,row);
                                    cellNum++;

                                    //优先级
                                    label = String.valueOf(detail.get("priority"));
                                    cell = row.createCell(cellNum);
                                    cellNum = setCellValue(cell,label,null,cellNum,null,row);
                                    cellNum++;

                                    //BPM文档链接
                                    label = String.valueOf(detail.get("documentUrl"));
                                    cell = row.createCell(cellNum);
                                    cellNum = setCellValue(cell,label,null,cellNum,null,row);

                                    cellNum = cellNum -1;
                                    cellNum = cellNum -1;
                                    cellNum = cellNum -1;
                                    cellNum = cellNum -1;
                                    cellNum = cellNum -1;

                                    if((detailList.size()-1)==detailIndex
                                            &&(midList.size()-1)==midIndex
                                            &&(itemList.size()-1)==itemIndex
                                            &&(groupList.size()-1)==groupIndex
                                            &&(centerList.size()-1)==centerIndex
                                            &&(it2.size() -1)==departmentIndex){
                                        continue;
                                    }
                                    detailIndex++;
                                    index++;
                                    row = sheet.createRow(index);
                                }
                                midIndex++;
                                cellNum = cellNum -1;
                            }

                            itemIndex++;
                            cellNum = cellNum -1;
                            cellNum = cellNum -1;
                            cellNum = cellNum -1;
                            cellNum = cellNum -1;
                            cellNum = cellNum -1;
                        }
                        groupIndex++;
                        cellNum = cellNum -1;
                    }
                    centerIndex++;
                    cellNum = cellNum -1;
                }
                departmentIndex++;
                cellNum = cellNum -1;
            }
        }
        Integer startRow = 1;
        Integer overRow = 0;
        int preRow = 1;
        for(JSONObject jsonObject :array) {

            int departmentSize = 0;
            int centerSize = 0;
            int groupSize = 0;
            int itemSize = 0;
            int midSize = 0;
            int detailSize = 0;

            Integer startCol = 0;
            Integer overCol = 0;

            //获取阶段下的部门列表
            LinkedHashSet<JSONObject> it2 =(LinkedHashSet<JSONObject>)jsonObject.get("children");
            if(it2 == null){
                return ;
            }
            //合并单元格
            //往excel里写值
            for (JSONObject department : it2) {

                LinkedHashSet<JSONObject> centerList = (LinkedHashSet<JSONObject>) department.get("children");
                if (centerList == null || centerList.isEmpty()) {
                    detailSize++;
                    midSize++;
                    groupSize++;
                    itemSize++;
                    centerSize++;
                    departmentSize++;
                    continue;
                }
                for (JSONObject center : centerList) {
                    //获取小组
                    LinkedHashSet<JSONObject> groupList = (LinkedHashSet<JSONObject>) center.get("children");
                    if (groupList == null || groupList.isEmpty()) {
                        detailSize++;
                        midSize++;
                        groupSize++;
                        itemSize++;
                        continue;
                    }
                    for (JSONObject group : groupList) {

                        LinkedHashSet<JSONObject> itemList = (LinkedHashSet<JSONObject>) group.get("children");
                        if(itemList==null || itemList.isEmpty()){
                            detailSize++;
                            midSize++;
                            itemSize++;
                            continue;
                        }

                        for(JSONObject item : itemList){
                            LinkedHashSet<JSONObject> midList = (LinkedHashSet<JSONObject>) item.get("children");
                            if(midList == null || midList.isEmpty()){
                                detailSize++;
                                midSize++;
                                continue;
                            }

                            for(JSONObject mid : midList){
                                LinkedHashSet<JSONObject> detailList = (LinkedHashSet<JSONObject>) mid.get("children");
                                if(detailList == null || detailList.isEmpty()){
                                    continue;
                                }
                                //对应BUG/问题/风险链接
                                if (detailList != null && !detailList.isEmpty()) {
                                    for (JSONObject detail : detailList) {
                                        detailSize++;
                                    }
                                } else {
                                    detailSize++;
                                }

                                //不合格问题及跟进
                                startRow = preRow + midSize;
                                overRow = preRow + detailSize-1;
                                startCol = 9;
                                overCol = 9;
                                if (overRow > startRow) {
                                    sheet.addMergedRegion(new CellRangeAddress(startRow, overRow, startCol, overCol));
                                }

                                midSize = detailSize;
                            }

                            startRow = preRow + itemSize;
                            overRow = preRow +detailSize-1;
                            if (overRow > startRow) {
                                //点检项次
                                startCol = 4;
                                overCol = 4;
                                sheet.addMergedRegion(new CellRangeAddress(startRow, overRow, startCol, overCol));
                                //点检结果
                                startCol = 5;
                                overCol = 5;
                                sheet.addMergedRegion(new CellRangeAddress(startRow, overRow, startCol, overCol));
                                //点检人
                                startCol = 6;
                                overCol = 6;
                                sheet.addMergedRegion(new CellRangeAddress(startRow, overRow, startCol, overCol));
                                //附件
                                startCol = 7;
                                overCol = 7;
                                sheet.addMergedRegion(new CellRangeAddress(startRow, overRow, startCol, overCol));
                                //备注
                                startCol = 8;
                                overCol = 8;
                                sheet.addMergedRegion(new CellRangeAddress(startRow, overRow, startCol, overCol));
                            }

                            itemSize = detailSize;
                        }

                        //小组
                        startRow = preRow + groupSize;
                        overRow = preRow + detailSize-1;
                        startCol = 3;
                        overCol = 3;
                        if (overRow > startRow) {
                            sheet.addMergedRegion(new CellRangeAddress(startRow, overRow, startCol, overCol));
                        }

                        groupSize = detailSize;
                    }

                    //中心
                    startRow = preRow + centerSize;
                    overRow = preRow +detailSize-1;
                    startCol = 2;
                    overCol = 2;
                    if (overRow > startRow) {
                        sheet.addMergedRegion(new CellRangeAddress(startRow, overRow, startCol, overCol));
                    }

                    centerSize = detailSize;
                }

                //部门
                startRow = preRow + departmentSize;
                overRow = preRow + detailSize-1;
                startCol = 1;
                overCol = 1;
                if (overRow > startRow) {
                    sheet.addMergedRegion(new CellRangeAddress(startRow, overRow, startCol, overCol));
                }

                departmentSize = detailSize;
            }

            //阶段
            startRow = preRow ;
            overRow = preRow + detailSize-1;
            startCol = 0;
            overCol = 0;
            if (overRow > startRow) {
                sheet.addMergedRegion(new CellRangeAddress(startRow, overRow, startCol, overCol));
            }
            preRow = preRow + detailSize;
            startRow = preRow + detailSize-1;
        }












    }




    public static <T> void writeItemExcel(Map<String,String> headers, LinkedHashSet<JSONObject> array, OutputStream out,int flag) {

        // 声明一个工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 生成一个表格
        HSSFSheet sheet = workbook.createSheet();

        //生成sheet内容
        getSheet(headers, array, flag, workbook, sheet);

        sheet.setDefaultRowHeight((short)300.0);
        sheet.setDefaultColumnWidth(30);

        try {
            workbook.write(out);
            out.flush();
            out.close();
        } catch (IOException e) {
            LG.error(e.toString(), e);
        }

    }

    private static void getSheet(Map<String, String> headers, LinkedHashSet<JSONObject>  array, int flag, HSSFWorkbook workbook, HSSFSheet sheet) {
        // 产生表格标题行
        HSSFRow row = sheet.createRow(0);

        // 标题行转中文
        Set<String> keys = headers.keySet();

        Iterator<String> it1 = keys.iterator();
        String key = "";    //存放临时键变量
        int c= 0;   //标题列数
        while (it1.hasNext()){
            key = it1.next();
            if (headers.containsKey(key)) {
                HSSFCell cell = row.createCell(c);
                HSSFRichTextString text = new HSSFRichTextString(headers.get(key));
                cell.setCellValue(text);
                c++;
            }
        }


        // 遍历集合数据,产生数据行
        int index = 0;

        for(JSONObject jsonObject :array){

            String label = String.valueOf(jsonObject.get("label"));

            index++;
            row = sheet.createRow(index);

            int cellNum = 0;

            //阶段
            HSSFCell cell = row.createCell(cellNum);
            cellNum = setCellValue(cell,label,null,cellNum,null,row);

            cellNum++;

            //获取阶段下的部门列表
            LinkedHashSet<JSONObject> it2 =(LinkedHashSet<JSONObject>)jsonObject.get("children");
            if(it2 == null || it2.isEmpty()){
                return ;
            }
            int departmentIndex =0;
            //往excel里写值
            for (JSONObject department : it2){

                //获取部门
                label = String.valueOf(department.get("label"));
                cell = row.createCell(cellNum);

                cellNum = setCellValue(cell,label,null,cellNum,null,row);

                cellNum++;

                LinkedHashSet<JSONObject> centerList = (LinkedHashSet<JSONObject>)department.get("children");

                if(centerList==null || centerList.isEmpty()){
                    index++;
                    cellNum = cellNum -1;
                    //row = sheet.createRow(index);

                    continue;
                }
                int centerIndex =0;
                for (JSONObject center : centerList){

                    //获取中心
                    label = String.valueOf(center.get("label"));
                    cell = row.createCell(cellNum);

                    LinkedHashSet<JSONObject> groupList = (LinkedHashSet<JSONObject>)center.get("children");

                    cellNum = setCellValue(cell,label,null,cellNum,null,row);

                    cellNum++;

                    if(groupList==null || groupList.isEmpty()){
                        index++;
                        cellNum = cellNum -1;
                        row = sheet.createRow(index);

                        continue;
                    }
                    int groupIndex =0;
                    for (JSONObject group : groupList){

                        //获取小组
                        label = String.valueOf(group.get("label"));
                        cell = row.createCell(cellNum);

                        cellNum = setCellValue(cell,label,null,cellNum,null,row);

                        cellNum++;

                        LinkedHashSet<JSONObject> itemList = (LinkedHashSet<JSONObject>)group.get("children");

                        if(itemList==null || itemList.isEmpty()){
                            index++;
                            cellNum = cellNum -1;
                            row = sheet.createRow(index);

                            continue;
                        }
                        int itemIndex =0;
                        for (JSONObject item : itemList){

                            //获取项次
                            label = String.valueOf(item.get("label"));
                            cell = row.createCell(cellNum);

                            cellNum = setCellValue(cell,label,null,cellNum,null,row);

                            cellNum++;
                            if(flag == 0){

                                label = String.valueOf(item.get("comment"));
                                cell = row.createCell(cellNum);

                                cellNum = setCellValue(cell,label,null,cellNum,null,row);
                            }
                            else if(flag == 1){
                                label = String.valueOf(item.get("result"));
                                cell = row.createCell(cellNum);
                                cellNum = setCellValue(cell,label,null,cellNum,null,row);
                                cellNum++;

                                label = String.valueOf(item.get("responMan"));
                                cell = row.createCell(cellNum);
                                cellNum = setCellValue(cell,label,null,cellNum,null,row);
                                cellNum++;


                                label = String.valueOf(item.get("attachmentName"));
                                cell = row.createCell(cellNum);
                                cellNum = setCellValue(cell,label,null,cellNum,null,row);
                                cellNum++;

                                label = String.valueOf(item.get("resultComment"));
                                cell = row.createCell(cellNum);
                                cellNum = setCellValue(cell,label,null,cellNum,null,row);

                                cellNum = cellNum-1;
                                cellNum = cellNum-1;
                                cellNum = cellNum-1;
                            }
                            cellNum = cellNum-1;

                            if(itemIndex == (itemList.size()-1) && (groupList.size()-1) ==groupIndex
                                    && centerIndex== (centerList.size()-1)
                                    && departmentIndex == (it2.size() -1)){
                                continue;
                            }
                            itemIndex++;
                            index++;
                            row = sheet.createRow(index);

                        }
                        groupIndex++;
                        cellNum = cellNum -1;
                    }
                    centerIndex++;
                    cellNum = cellNum -1;
                }
                departmentIndex++;
                cellNum = cellNum -1;
            }
        }
        Integer startRow = 1;
        Integer overRow = 0;
        int preRow = 1;
        for(JSONObject jsonObject :array) {

            int departmentSize = 0;
            int centerSize = 0;
            int groupSize = 0;


            //获取阶段下的部门列表
            int itemSize = 0;

            Integer startCol = 0;
            Integer overCol = 0;
            int emptyIndex = 0;

            //获取阶段下的部门列表
            LinkedHashSet<JSONObject> it2 =(LinkedHashSet<JSONObject>)jsonObject.get("children");
            if(it2 == null){
                return ;
            }
            //合并单元格
            //往excel里写值
            for (JSONObject department : it2) {

                LinkedHashSet<JSONObject> centerList = (LinkedHashSet<JSONObject>) department.get("children");
                if (centerList == null || centerList.isEmpty()) {
                    //emptyIndex ++;
                    groupSize++;
                    itemSize++;
                    centerSize++;
                    departmentSize++;
                    continue;
                }
                for (JSONObject center : centerList) {
                    //获取小组
                    LinkedHashSet<JSONObject> groupList = (LinkedHashSet<JSONObject>) center.get("children");
                    if (groupList == null || groupList.isEmpty()) {
                        //emptyIndex ++;
                        groupSize++;
                        itemSize++;

                        continue;
                    }
                    for (JSONObject group : groupList) {

                        LinkedHashSet<JSONObject> itemList = (LinkedHashSet<JSONObject>) group.get("children");

                        if(itemList==null || itemList.isEmpty()){

                            continue;
                        }

                        if (itemList != null && !itemList.isEmpty()) {
                            for (JSONObject item : itemList) {
                                itemSize++;
                            }
                        } else {
                            itemSize++;
                        }

                        startRow = preRow + groupSize;
                        overRow = preRow + itemSize-1;
                        startCol = 3;
                        overCol = 3;
                        if (overRow > startRow) {
                           sheet.addMergedRegion(new CellRangeAddress(startRow, overRow, startCol, overCol));
                        }

                        groupSize = itemSize;
                    }
                    startRow = preRow + centerSize;
                    overRow = preRow +itemSize-1;
                    startCol = 2;
                    overCol = 2;
                    if (overRow > startRow) {
                       sheet.addMergedRegion(new CellRangeAddress(startRow, overRow, startCol, overCol));
                    }

                    centerSize = itemSize;
                }


                startRow = preRow + departmentSize;
                overRow = preRow + itemSize-1;
                startCol = 1;
                overCol = 1;
                if (overRow > startRow) {
                    sheet.addMergedRegion(new CellRangeAddress(startRow, overRow, startCol, overCol));
                }

                departmentSize = itemSize;
            }

            startRow = preRow ;
            overRow = preRow + itemSize-1;
            startCol = 0;
            overCol = 0;
            if (overRow > startRow) {
                sheet.addMergedRegion(new CellRangeAddress(startRow, overRow, startCol, overCol));
            }
            preRow = preRow + itemSize;
            startRow = preRow + itemSize-1;
        }
    }

    /**
     * 每个sheet的写入
     *
     * @param sheet   页签
     * @param headers 表头
     * @param dataset 数据集合
     * @param pattern 日期格式
     */
    private static <T> void write2Sheet(HSSFSheet sheet, Map<String,String> headers, Collection<T> dataset,
                                        String pattern,HSSFWorkbook workbook) {
        //时间格式默认"yyyy-MM-dd"
        if (StringUtils.isEmpty(pattern)){
            pattern = "yyyy-MM-dd";
        }
        HSSFFont titleFont = workbook.createFont();

        titleFont.setFontHeightInPoints((short) 14);
        CellStyle titleStyle = workbook.createCellStyle();
        titleStyle.setFont(titleFont);

        titleStyle.setAlignment(HorizontalAlignment.CENTER);

        // 产生表格标题行
        HSSFRow row = sheet.createRow(0);
        // 标题行转中文
        Set<String> keys = headers.keySet();
        Iterator<String> it1 = keys.iterator();
        String key = "";    //存放临时键变量
        int c= 0;   //标题列数
        while (it1.hasNext()){
            key = it1.next();
            if (headers.containsKey(key)) {
                HSSFCell cell = row.createCell(c);
                cell.setCellStyle(titleStyle);
                HSSFRichTextString text = new HSSFRichTextString(headers.get(key));
                if("问题来源".equals(headers.get(key))|| "专业组".equals(headers.get(key)) || "严重等级".equals(headers.get(key))
                        || "问题状态".equals(headers.get(key))|| "当前处理人".equals(headers.get(key))|| "文档编号".equals(headers.get(key))
                        || "问题重要度".equals(headers.get(key))
                        || "文档状态".equals(headers.get(key)) || "项目编号".equals(headers.get(key))|| "故障类别".equals(headers.get(key))
                        || "功能模块".equals(headers.get(key))){
                    sheet.setColumnWidth(c,  (int)((50 + 0.72) * 60));
                }

                cell.setCellValue(text);
                c++;
            }
        }

        HSSFCellStyle hlink_style = workbook.createCellStyle();
        HSSFFont hlink_font = workbook.createFont();
        hlink_font.setUnderline(HSSFFont.U_SINGLE);
        hlink_font.setColor(HSSFColor.HSSFColorPredefined.BLUE.getIndex());
        hlink_style.setFont(hlink_font);

        titleFont.setFontHeightInPoints((short) 10);
        titleStyle = workbook.createCellStyle();
        titleStyle.setFont(titleFont);
        titleStyle.setAlignment(HorizontalAlignment.CENTER);
        CreationHelper createHelper = workbook.getCreationHelper();
        // 遍历集合数据,产生数据行
        Iterator<T> it = dataset.iterator();
        HSSFCell cell = null;
        Field field = null;
        int index = 0;
        while (it.hasNext()) {
            index++;
            row = sheet.createRow(index);
            T t = it.next();
            try {
                if (t instanceof Map) {
                    Map<String, Object> map = (Map<String, Object>) t;
                    int cellNum = 0;
                    //遍历列名
                    Iterator<String> it2 = keys.iterator();
                    while (it2.hasNext()){
                        key = it2.next();
                        if (!headers.containsKey(key)) {
                            LG.error("Map 中 不存在 key [" + key + "]");
                            continue;
                        }
                        Object value = map.get(key);
                        cell = row.createCell(cellNum);
                        cell.setCellStyle(titleStyle);

                        //文档编号加上链接
                        if("documentNum".equals(key)){
                            String[] strArray = String.valueOf(value).split("\\+++");
                            if(strArray.length>1){

                                org.apache.poi.hssf.usermodel.HSSFHyperlink  link = (org.apache.poi.hssf.usermodel.HSSFHyperlink) createHelper.createHyperlink(HyperlinkType.URL);

                                link.setAddress(strArray[1]);
                                cell.setHyperlink(link);
                                cell.setCellStyle(hlink_style);
                            }
                            if(strArray!=null && strArray.length>=1){

                                cell.setCellValue(strArray[0]);
                            }
                            else{
                                cell.setCellValue("");
                            }
                        }else{
                            cellNum = setCellValue(cell,value,pattern,cellNum,null,row);
                        }


                        cellNum++;
                    }
                } else {
                    List<FieldForSortting> fields = sortFieldByAnno(t.getClass());
                    int cellNum = 0;
                    for (int i = 0; i < fields.size(); i++) {
                        cell = row.createCell(cellNum);
                        field = fields.get(i).getField();
                        field.setAccessible(true);
                        Object value = field.get(t);
                        cellNum = setCellValue(cell,value,pattern,cellNum,field,row);
                        cellNum++;
                    }
                }
            } catch (Exception e) {
                LG.error(e.toString(), e);
            }
        }
        sheet.setDefaultColumnWidth(30);
    }


    /**
     * 每个sheet的写入
     *
     * @param sheet   页签
     * @param headers 表头
     * @param dataset 数据集合
     * @param pattern 日期格式
     */
    private static <T> void write4Sheet(HSSFSheet sheet, Map<String,String> headers, List<Map<String, Object>> dataset,
                                        String pattern,HSSFWorkbook workbook,List<ProjectTypeStageAllOutVO> list,ProjectTypeStageInVO vo) throws ParseException {
        //时间格式默认"yyyy-MM-dd"
        if (StringUtils.isEmpty(pattern)){
            pattern = "yyyy-MM-dd";
        }
        HSSFFont titleFont = workbook.createFont();

        titleFont.setFontHeightInPoints((short) 14);
        CellStyle titleStyle = workbook.createCellStyle();
        titleStyle.setFont(titleFont);

        titleStyle.setAlignment(HorizontalAlignment.CENTER);

        // 产生表格标题行
        HSSFRow row = sheet.createRow(0);
        // 标题行转中文
        Set<String> keys = headers.keySet();
        Iterator<String> it1 = keys.iterator();
        String key = "";    //存放临时键变量
        int c= 0;   //标题列数
        while (it1.hasNext()){
            key = it1.next();
            if (headers.containsKey(key)) {
                HSSFCell cell = row.createCell(c);
                cell.setCellStyle(titleStyle);
                HSSFRichTextString text = new HSSFRichTextString(headers.get(key));
                cell.setCellValue(text);
                c++;
            }
        }

        titleFont.setFontHeightInPoints((short) 10);
        titleStyle = workbook.createCellStyle();
        titleStyle.setFont(titleFont);
        titleStyle.setAlignment(HorizontalAlignment.CENTER);

        // 遍历集合数据,产生数据行
         headers =  headers;


        Row row3;
        int kk=0;
        row3 = sheet.createRow((short) 0);
        for (String key1 : headers.keySet()) {
            row3.createCell((short) kk).setCellValue(String.valueOf(headers.get(key1)));
            kk=kk+1;
        }
        for(int i=0;i<dataset.size();i++) {
            row3 = sheet.createRow((short) i+1);
            List rowData = new ArrayList();
            Map<String, Object> hashMap = dataset.get(i);
            kk=0;
            for (String key1 : headers.keySet()) {
                if (dataset.get(i).get(key1) == null) {
                    rowData.add("");
                    row3.createCell((short) kk).setCellValue("");
                } else {
//                    rowData.add(dataset.get(i).get(key1));
                    String name =  String.valueOf(hashMap.get(key1));
                    if(name!=null){
                        int as = 1;
                    }
                    if("项目编号".equals(key1)){
                        String[] names = (String[]) hashMap.get(key1);
                        String namez = "";
                        for(int m=0;m<names.length;m++){
                            namez = namez +","+names[m];
                        }
                        if("".equals(namez)){

                        }else{
                            namez = namez.substring(1);
                        }
                        row3.createCell((short) kk).setCellValue(namez);
                    }else{
                        row3.createCell((short) kk).setCellValue(name);
                    }
                }
                kk=kk+1;
            }
        }



        sheet.setDefaultColumnWidth(30);

        List<ProjectTypeStageAllOutVO> lists = list;

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date stDate = vo.getStartDate();
        Date endDate = vo.getEndDate();
        long from1 = stDate.getTime();
        long to1 = endDate.getTime();
        int days = (int) ((to1 - from1) / (1000 * 60 * 60 * 24));
        //导出标题头 根据筛选条件循环复制标题头
        LinkedHashMap<String, Integer> linkMap = new LinkedHashMap<>();
        int num = 5;
        for(int k=0;k<days;k++){
            String kDate = "";
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(stDate);
            calendar.add(Calendar.DAY_OF_MONTH, +k);//+1今天的时间加一天
            kDate = dateFormat.format(calendar.getTime());
            headers.put(kDate, kDate);
            linkMap.put(kDate,num+k);
        }



        List<Short> listColor = new ArrayList<>();
        listColor.add(HSSFColor.HSSFColorPredefined.GOLD.getIndex());
        listColor.add(HSSFColor.HSSFColorPredefined.YELLOW.getIndex());
        listColor.add(HSSFColor.HSSFColorPredefined.BRIGHT_GREEN.getIndex());
        listColor.add(HSSFColor.HSSFColorPredefined.TURQUOISE.getIndex());
        listColor.add(HSSFColor.HSSFColorPredefined.DARK_RED.getIndex());
        listColor.add(HSSFColor.HSSFColorPredefined.SKY_BLUE.getIndex());
        listColor.add(HSSFColor.HSSFColorPredefined.PLUM.getIndex());
        listColor.add(HSSFColor.HSSFColorPredefined.GREY_25_PERCENT.getIndex());
        listColor.add(HSSFColor.HSSFColorPredefined.ROSE.getIndex());
        listColor.add(HSSFColor.HSSFColorPredefined.LIGHT_YELLOW.getIndex());
        listColor.add(HSSFColor.HSSFColorPredefined.LIGHT_GREEN.getIndex());

        listColor.add(HSSFColor.HSSFColorPredefined.LIGHT_TURQUOISE.getIndex());
        listColor.add(HSSFColor.HSSFColorPredefined.PALE_BLUE.getIndex());
        listColor.add(HSSFColor.HSSFColorPredefined.LAVENDER.getIndex());
        listColor.add(HSSFColor.HSSFColorPredefined.CORNFLOWER_BLUE.getIndex());
        listColor.add(HSSFColor.HSSFColorPredefined.LEMON_CHIFFON.getIndex());



        for(int i=0;i<list.size();i++){
            int rNum = i+1;
            Row row2 = sheet.getRow(rNum);
            CellStyle cellStyle = workbook.createCellStyle();

            List<ProjectTypeStageOutVO> listInfoStage = list.get(i).getListInfoStage();
            HashMap<String,Integer> numMap = new HashMap<>();
            for(int m=0;m<listInfoStage.size();m++){
                ProjectTypeStageOutVO voN = listInfoStage.get(m);
                Date stDateN = dateFormat.parse(voN.getStartDate());
                Date endDateN = dateFormat.parse(voN.getEndDate());
                long from1N = stDateN.getTime();
                long to1N = endDateN.getTime();
                int daysN = (int) ((to1N - from1N) / (1000 * 60 * 60 * 24));
                //根据日期 一个单元格一个单元格赋值,同时记录下位置
                for(int k=0;k<daysN;k++){
                    String kDate = "";
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(stDateN);
                    calendar.add(Calendar.DAY_OF_MONTH, +k);//+1今天的时间加一天
                    Integer startNum = linkMap.get(dateFormat.format(stDateN));
                    if(startNum==null){
                        kDate = dateFormat.format(stDate);
                    }else{
                        kDate = dateFormat.format(calendar.getTime());
                    }
                    Integer nums = linkMap.get(kDate);
                    if (k > listColor.size()) {
                        cellStyle.setFillForegroundColor(HSSFColor.HSSFColorPredefined.LAVENDER.getIndex());
                    } else {
                        cellStyle.setFillForegroundColor(listColor.get(k));
                    }
                    cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                    cellStyle.setAlignment(HorizontalAlignment.CENTER);
                    if(nums!=null){
                        row2.getCell(nums).setCellStyle(cellStyle);
                    }
                }
                Integer startNum = linkMap.get(dateFormat.format(stDateN));
                if(startNum==null){
                    startNum = 5;
                }
                Integer endNum = linkMap.get(dateFormat.format(endDateN));
                if(endNum==null){
                    endNum = 5+linkMap.size()-1;
                }
                int maxNum = numMap.get("max")==null?0:numMap.get("max");
                //如果有重合部分 则从前一个合并单元格的下一列开始
                if(startNum<maxNum){
                    startNum = maxNum +1;
                }
                CellRangeAddress region = new CellRangeAddress(rNum, rNum, startNum, endNum);
                if(startNum==endNum){

                }else{
                    sheet.addMergedRegion(region);
                }
                HSSFCellStyle style = workbook.createCellStyle();
                style.setAlignment(HorizontalAlignment.CENTER);	//左右居中
                    /*var cell = sheet.getRow(rNum).getCell(index["firstCol"]);
                    cell.CellStyle = cellstyle;*/
                if(endNum>maxNum){
                    maxNum=endNum;
                }
                numMap.put("max",maxNum);
            }
        }

    }

    private static int setCellValue(HSSFCell cell,Object value,String pattern,int cellNum,Field field,HSSFRow row){
        String textValue = null;
        if (value instanceof Integer) {
            int intValue = (Integer) value;
            cell.setCellValue(intValue);
        } else if (value instanceof Float) {
            float fValue = (Float) value;
            cell.setCellValue(fValue);
        } else if (value instanceof Double) {
            double dValue = (Double) value;
            cell.setCellValue(dValue);
        } else if (value instanceof Long) {
            long longValue = (Long) value;
            cell.setCellValue(longValue);
        } else if (value instanceof Boolean) {
            boolean bValue = (Boolean) value;
            cell.setCellValue(bValue);
        } else if (value instanceof Date) {
            Date date = (Date) value;
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
            textValue = sdf.format(date);
        } else if (value instanceof String[]) {
            String[] strArr = (String[]) value;
            for (int j = 0; j < strArr.length; j++) {
                String str = strArr[j];
                cell.setCellValue(str);
                if (j != strArr.length - 1) {
                    cellNum++;
                    cell = row.createCell(cellNum);
                }
            }
        } else if (value instanceof Double[]) {
            Double[] douArr = (Double[]) value;
            for (int j = 0; j < douArr.length; j++) {
                Double val = douArr[j];
                // 值不为空则set Value
                if (val != null) {
                    cell.setCellValue(val);
                }

                if (j != douArr.length - 1) {
                    cellNum++;
                    cell = row.createCell(cellNum);
                }
            }
        } else {
            // 其它数据类型都当作字符串简单处理
            String empty = StringUtils.EMPTY;
            if(field != null) {
                ExcelCell anno = field.getAnnotation(ExcelCell.class);
                if (anno != null) {
                    empty = anno.defaultValue();
                }
            }
            textValue = value == null ? empty : value.toString();
        }
        if (textValue != null) {
            HSSFRichTextString richString = new HSSFRichTextString(textValue);
            if("null".equals(textValue)){
                cell.setCellValue("");
            }
            else{
                cell.setCellValue(richString);
            }

        }
        return cellNum;
    }

    /**
     * 把Excel的数据封装成voList
     *
     * @param clazz       vo的Class
     * @param inputStream excel输入流
     * @param pattern     如果有时间数据,设定输入格式。默认为"yyy-MM-dd"
     * @param logs        错误log集合
     * @param arrayCount  如果vo中有数组类型,那就按照index顺序,把数组应该有几个值写上.
     * @return voList
     * @throws RuntimeException
     */
    @SuppressWarnings("unchecked")
    public static <T> Collection<T> importExcel(Class<T> clazz, InputStream inputStream,
                                                String pattern, ExcelLogs logs, Integer... arrayCount) {
        Workbook workBook;
        try {
            workBook = WorkbookFactory.create(inputStream);
        } catch (Exception e) {
            LG.error("load excel file error",e);
            return null;
        }
        List<T> list = new ArrayList<>();
        Sheet sheet = workBook.getSheetAt(0);
        Iterator<Row> rowIterator = sheet.rowIterator();
        try {
            List<ExcelLog> logList = new ArrayList<>();
            // Map<title,index>
            Map<String, Integer> titleMap = new HashMap<>();

            while (rowIterator.hasNext()) {
                Row row = rowIterator.next();
                if (row.getRowNum() == 0) {
                    if (clazz == Map.class) {
                        // 解析map用的key,就是excel标题行
                        Iterator<Cell> cellIterator = row.cellIterator();
                        Integer index = 0;
                        while (cellIterator.hasNext()) {
                            String value = cellIterator.next().getStringCellValue();
                            titleMap.put(value, index);
                            index++;
                        }
                    }
                    continue;
                }
                // 整行都空,就跳过
                boolean allRowIsNull = true;
                Iterator<Cell> cellIterator = row.cellIterator();
                while (cellIterator.hasNext()) {
                    Object cellValue = getCellValue(cellIterator.next());
                    if (cellValue != null) {
                        allRowIsNull = false;
                        break;
                    }
                }
                if (allRowIsNull) {
                    LG.warn("Excel row " + row.getRowNum() + " all row value is null!");
                    continue;
                }
                StringBuilder log = new StringBuilder();
                if (clazz == Map.class) {
                    Map<String, Object> map = new HashMap<>();
                    for (String k : titleMap.keySet()) {
                        Integer index = titleMap.get(k);
                        Cell cell = row.getCell(index);
                        // 判空
                        if (cell == null) {
                            map.put(k, null);
                        } else {
                            cell.setCellType(CellType.STRING);
                            String value = cell.getStringCellValue();
                            map.put(k, value);
                        }
                    }
                    list.add((T) map);

                } else {
                    T t = clazz.newInstance();
                    int arrayIndex = 0;// 标识当前第几个数组了
                    int cellIndex = 0;// 标识当前读到这一行的第几个cell了
                    List<FieldForSortting> fields = sortFieldByAnno(clazz);
                    for (FieldForSortting ffs : fields) {
                        Field field = ffs.getField();
                        field.setAccessible(true);
                        if (field.getType().isArray()) {
                            Integer count = arrayCount[arrayIndex];
                            Object[] value;
                            if (field.getType().equals(String[].class)) {
                                value = new String[count];
                            } else {
                                // 目前只支持String[]和Double[]
                                value = new Double[count];
                            }
                            for (int i = 0; i < count; i++) {
                                Cell cell = row.getCell(cellIndex);
                                String errMsg = validateCell(cell, field, cellIndex);
                                if (StringUtils.isBlank(errMsg)) {
                                    value[i] = getCellValue(cell);
                                } else {
                                    log.append(errMsg);
                                    log.append(";");
                                    logs.setHasError(true);
                                }
                                cellIndex++;
                            }
                            field.set(t, value);
                            arrayIndex++;
                        } else {
                            Cell cell = row.getCell(cellIndex);
                            String errMsg = validateCell(cell, field, cellIndex);
                            if (StringUtils.isBlank(errMsg)) {
                                Object value = null;
                                // 处理特殊情况,Excel中的String,转换成Bean的Date
                                if (field.getType().equals(Date.class)
                                        && cell.getCellTypeEnum() == CellType.STRING) {
                                    Object strDate = getCellValue(cell);
                                    try {
                                        value = new SimpleDateFormat(pattern).parse(strDate.toString());
                                    } catch (ParseException e) {

                                        errMsg =
                                                MessageFormat.format("the cell [{0}] can not be converted to a date ",
                                                        CellReference.convertNumToColString(cell.getColumnIndex()));
                                    }
                                } else {
                                    value = getCellValue(cell);
                                    // 处理特殊情况,excel的value为String,且bean中为其他,且defaultValue不为空,那就=defaultValue
                                    ExcelCell annoCell = field.getAnnotation(ExcelCell.class);
                                    if (value instanceof String && !field.getType().equals(String.class)
                                            && StringUtils.isNotBlank(annoCell.defaultValue())) {
                                        value = annoCell.defaultValue();
                                    }
                                }
                                field.set(t, value);
                            }
                            if (StringUtils.isNotBlank(errMsg)) {
                                log.append(errMsg);
                                log.append(";");
                                logs.setHasError(true);
                            }
                            cellIndex++;
                        }
                    }
                    list.add(t);
                    logList.add(new ExcelLog(t, log.toString(), row.getRowNum() + 1));
                }
            }
            logs.setLogList(logList);
        } catch (InstantiationException e) {
            throw new RuntimeException(MessageFormat.format("can not instance class:{0}",
                    clazz.getSimpleName()), e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(MessageFormat.format("can not instance class:{0}",
                    clazz.getSimpleName()), e);
        }
        return list;
    }

    /**
     * 驗證Cell類型是否正確
     *
     * @param cell    cell單元格
     * @param field   欄位
     * @param cellNum 第幾個欄位,用於errMsg
     * @return
     */
    private static String validateCell(Cell cell, Field field, int cellNum) {
        String columnName = CellReference.convertNumToColString(cellNum);
        String result = null;
        CellType[] cellTypeArr = validateMap.get(field.getType());
        if (cellTypeArr == null) {
            result = MessageFormat.format("Unsupported type [{0}]", field.getType().getSimpleName());
            return result;
        }
        ExcelCell annoCell = field.getAnnotation(ExcelCell.class);
        if (cell == null
                || (cell.getCellTypeEnum() == CellType.STRING && StringUtils.isBlank(cell
                .getStringCellValue()))) {
            if (annoCell != null && annoCell.valid().allowNull() == false) {
                result = MessageFormat.format("the cell [{0}] can not null", columnName);
            }
            ;
        } else if (cell.getCellTypeEnum() == CellType.BLANK && annoCell.valid().allowNull()) {
            return result;
        } else {
            List<CellType> cellTypes = Arrays.asList(cellTypeArr);

            // 如果類型不在指定範圍內,並且沒有默認值
            if (!(cellTypes.contains(cell.getCellTypeEnum()))
                    || StringUtils.isNotBlank(annoCell.defaultValue())
                    && cell.getCellTypeEnum() == CellType.STRING) {
                StringBuilder strType = new StringBuilder();
                for (int i = 0; i < cellTypes.size(); i++) {
                    CellType cellType = cellTypes.get(i);
                    strType.append(getCellTypeByInt(cellType));
                    if (i != cellTypes.size() - 1) {
                        strType.append(",");
                    }
                }
                result =
                        MessageFormat.format("the cell [{0}] type must [{1}]", columnName, strType.toString());
            } else {
                // 类型符合验证,但值不在要求范围内的
                // String in
                if (annoCell.valid().in().length != 0 && cell.getCellTypeEnum() == CellType.STRING) {
                    String[] in = annoCell.valid().in();
                    String cellValue = cell.getStringCellValue();
                    boolean isIn = false;
                    for (String str : in) {
                        if (str.equals(cellValue)) {
                            isIn = true;
                        }
                    }
                    if (!isIn) {
                        result = MessageFormat.format("the cell [{0}] value must in {1}", columnName, in);
                    }
                }
                // 数字型
                if (cell.getCellTypeEnum() == CellType.NUMERIC) {
                    double cellValue = cell.getNumericCellValue();
                    // 小于
                    if (!Double.isNaN(annoCell.valid().lt())) {
                        if (!(cellValue < annoCell.valid().lt())) {
                            result =
                                    MessageFormat.format("the cell [{0}] value must less than [{1}]", columnName,
                                            annoCell.valid().lt());
                        }
                    }
                    // 大于
                    if (!Double.isNaN(annoCell.valid().gt())) {
                        if (!(cellValue > annoCell.valid().gt())) {
                            result =
                                    MessageFormat.format("the cell [{0}] value must greater than [{1}]", columnName,
                                            annoCell.valid().gt());
                        }
                    }
                    // 小于等于
                    if (!Double.isNaN(annoCell.valid().le())) {
                        if (!(cellValue <= annoCell.valid().le())) {
                            result =
                                    MessageFormat.format("the cell [{0}] value must less than or equal [{1}]",
                                            columnName, annoCell.valid().le());
                        }
                    }
                    // 大于等于
                    if (!Double.isNaN(annoCell.valid().ge())) {
                        if (!(cellValue >= annoCell.valid().ge())) {
                            result =
                                    MessageFormat.format("the cell [{0}] value must greater than or equal [{1}]",
                                            columnName, annoCell.valid().ge());
                        }
                    }
                }
            }
        }
        return result;
    }

    /**
     * 根据annotation的seq排序后的栏位
     *
     * @param clazz
     * @return
     */
    private static List<FieldForSortting> sortFieldByAnno(Class<?> clazz) {
        Field[] fieldsArr = clazz.getDeclaredFields();
        List<FieldForSortting> fields = new ArrayList<>();
        List<FieldForSortting> annoNullFields = new ArrayList<>();
        for (Field field : fieldsArr) {
            ExcelCell ec = field.getAnnotation(ExcelCell.class);
            if (ec == null) {
                // 没有ExcelCell Annotation 视为不汇入
                continue;
            }
            int id = ec.index();
            fields.add(new FieldForSortting(field, id));
        }
        fields.addAll(annoNullFields);
        sortByProperties(fields, true, false, "index");
        return fields;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private static void sortByProperties(List<? extends Object> list, boolean isNullHigh,
                                         boolean isReversed, String... props) {
        if (CollectionUtils.isNotEmpty(list)) {
            Comparator<?> typeComp = ComparableComparator.getInstance();
            if (isNullHigh == true) {
                typeComp = ComparatorUtils.nullHighComparator(typeComp);
            } else {
                typeComp = ComparatorUtils.nullLowComparator(typeComp);
            }
            if (isReversed) {
                typeComp = ComparatorUtils.reversedComparator(typeComp);
            }

            List<Object> sortCols = new ArrayList<Object>();

            if (props != null) {
                for (String prop : props) {
                    sortCols.add(new BeanComparator(prop, typeComp));
                }
            }
            if (sortCols.size() > 0) {
                Comparator<Object> sortChain = new ComparatorChain(sortCols);
                Collections.sort(list, sortChain);
            }
        }
    }

}

三、导入

 @PostMapping(value = "/import.ajax")
    @ResponseBody
    @ApiOperation("导入")
    public Result importKeyParam(@RequestParam(required = true) MultipartFile file,
                                 @RequestParam(required = true) Integer importType,
                                 @RequestParam(required = true) Integer type) {
        // 文件名校验
        String fileName = file.getOriginalFilename();
        if (!fileName.matches(GenConstants.LOWEXCEL) && !fileName.matches(GenConstants.HIGHEXCEL)) {
            return ResultGenerator.genFailResult(ResultEnum.FILE_INCORRENT.getMessage());
        }
        // 文件大小校验
        if (file.getSize() / CommonConstant.FILE_FORMAT_SIZE / CommonConstant.FILE_FORMAT_SIZE > 0.1) {
            return ResultGenerator.genFailResult("文件过大,不能超过" + CommonConstant.BIG_EXCEL_SIZE + "KB");
        }

        Collection<Map> maps;
        try {
            maps = ExcelUtil.importExcel(Map.class, file.getInputStream(), "yyyy-MM-dd HH:mm:ss", new ExcelLogs(), 0);
        } catch (Exception e) {
            return ResultGenerator.genFailResult("请求或者文件有问题!");
        }
        if (maps == null || maps.size() == 0) {
            return ResultGenerator.genFailResult(ResultEnum.EMPTY_EXCEL_DATA.getMessage());
        }
        if (CustomFieldEnum.getByType(type) != null) {
            HashMap<String, String> headers = new LinkedHashMap<>();
            getExpostHeader(headers, type, true);
            try {
                List<Map> mapList = Arrays.asList(maps.toArray(new Map[0]));
                // 保存
                HashMap<String, Object> ret = getInterComService(type).importData(headers, mapList, importType, CustomFieldEnum.getByType(type));
                return ResultGenerator.genSuccessResult(ret);
            } catch (Exception e) {
                return ResultGenerator.genFailResult("导入失败:逻辑有误!");
            }
        } else {
            return ResultGenerator.genFailResult("导入失败:模块类型有误!");
        }
    }