一、背景

    目标效果是想导入 Excel 文档,后台接收并读取数据,再将数据传入到数据库中进行查询,得到结果后导出。

二、实现过程

    版本一:

        版本一和版本二的后台的代码都一样,所以这里主要讲解前端的处理,后端的参考版本二的介绍即可。

        首先在 form 表单中放置一个 type=‘file’ 的 input 标签

<form id="formFile" method="post" action="##"
	class="report_form" target="_blank">
	<div class="easyui-panel" title="Upload File"
		style="width: 450px; padding: 30px 70px 50px 70px">
		<div style="margin-bottom: 20px">
			<div>物料代码文件:</div>
			<input class="import-btn" type="file" accept=".xls,.xlsx">
		</div>
	</div>
</form>

 当选择文件发生变化时触发 Ajax 提交。简洁,就是页面不是很好看。

<script type="text/javascript">
	$(function () {
	    $('.import-btn').change(function () {
	          var formData = new FormData(),
	              name = $(this).val()
	              formData.append('file', $(this)[0].files[0])
	              // 此处可传入多个参数
	              formData.append('name', name)
	              console.log(name+', '+$(this)[0].files[0])
	          $.ajax({
	              url: "${ctx}/bom/getLatestOrder.do",
	              type: 'post',
	              async: false,
	              data: formData,
	              // 告诉jQuery不要去处理发送的数据
	              processData: false,
	              // 告诉jQuery不要去设置Content-Type请求头
	              contentType: false,
	              beforeSend: function () {
	                  console.log('正在进行,请稍候')
	              },
	              success: function (data) {
	            	  if (data.message != null) {
	                  	$.messager.alert("提示",data.message);
	                  }
	                  if (data.infos != null){
	                  	location.href = "${ctx }/bom/messageExport.do";
	                  }
	               }
	          })
	     })
    });
	
</script>

    版本二:

        我想用 EasyUI 的 filebox 来对文件框进行美化,所以做如下修改:

<form id="formFile" method="post" action="##" class="report_form" target="_blank">
	<div class="easyui-panel" title="Upload File"
	     style="width: 450px; padding: 30px 70px 50px 70px">
	     <div style="margin-bottom: 20px">
	        <div>物料代码文件:</div>
	    	<input class="easyui-filebox" id="fb" name="fb" type="text" 
                   style="width: 300px; height: 32px;">
	     </div>
	    <div>
	    	<a href="javascript:void(0)" class="easyui-linkbutton" style="width: 98%" 
                    onclick="submitForm()" id="submit">提交</a>
	    </div>
	</div>
     </form>

 改了一下,选择文件变化后是先去进行判断筛选,提交按钮才是触发与后台的交互。

<script type="text/javascript">
    $(function () {
        //添加对话框,上传控件初始化
        $('#fb').filebox({
            buttonText: '选择文件',  //按钮文本
            buttonAlign: 'right',   //按钮对齐
            //multiple: true,       //是否多文件方式
            accept: '.xls,.xlsx', //指定文件类型
            onChange: function (e) {
            	change(this);//上传处理
            }
        });
    });
	function change(_obj){
		var tempFile = $("#fb");
		var value=tempFile.filebox('getValue');
		// 取后缀名
		var ext=value.substring(value.lastIndexOf(".")+1).toLowerCase();
		if(ext==''){ // 未选择文件,不作处理
			return;
		}else if((ext!='xls') && (ext!='xlsx')){
		    $.messager.alert("消息提示", "文件格式需为*.xls或*.xlsx 类型", "warning");
			$('#fb').filebox('setValue',''); // 清空filebox回显框
		    return;
		}
	}
		             
    function submitForm(){
        var fd = new FormData();
        var file = document.getElementsByName("fb")[0].files[0];
        if (file === undefined) {
            $.messager.alert("提示","文件数据为空请正确上传文件!");
            return;
        }
        //上传的参数名 参数值 k-v键值对
        fd.append("file", file);
        $.ajax({
            url:"${ctx}/bom/getLatestOrder.do",
            type:"post",
            data:fd,
            async : true, //此处为异步加载
            processData: false, // 告诉jQuery不要去处理发送的数据
            contentType: false, // 告诉jQuery不要去设置Content-Type请求头
            beforeSend: function () {
                $("#submit").attr({ disabled: "disabled" });// 禁用按钮防止重复提交
        		$.messager.progress({ 
        			 title: '提示', 
        			 msg: '文件处理中,请稍候……', 
        			 text: '' 
        		});
            },
            success:function(data){
                 if (data.message != null) {
                 	$.messager.alert("提示",data.message);
                 }
                 if (data.infos != null){
                	 location.href = "${ctx }/bom/messageExport.do";
                 }
            },
            complete: function () {
            	$.messager.progress('close');
                $("#submit").removeAttr("disabled");
            },
            error:function(e){
                $.messager.alert("错误","服务器异常,请稍后重试!!!<br/>"+e.message);
            },
        });

    }
	
</script>

    代码我给了许多注释,我这就大致讲解一下。首先文本框的样式 class 设置为 filebox ,type 的值也改成 text ,并且是在 JS 中去设置选择文件的按钮样式,指定选择文件类型以及选择文件变化之后的判断。

    接着就是提交按钮,设置了 submitForm()方法,在方法中获取 file 文件,并通过 Ajax 传送到后台进行处理。 需要注意的是,在未换成 filebox 之前,使用 JQuery【 如:$("#fb").get(0).files[0] 】去获取文件是完全没有问题的,但一使用 filebox,就不能这样去获取文件了,会报如下错误

 Uncaught TypeError: Cannot read property '0' of null

所以只能像我上面的代码那样,使用原生的方法去获取【如:document.getElementsByName("fb")[0].files[0]; 】

    知识点:

---------------------------------------

        1、遇到的第一个问题,就是用 Ajax 提交,前后台都没有报错,但就是不会弹出下载框。原因就是导出excel,实际上是文件下载,后台需要往前端(浏览器)写文件流的。而Ajax请求获取数据都是“字符串”,整个交互传输用的都是字符串数据,它没法解析后台返回的文件流,但浏览器可以。

        因此,便有了上面的解决办法,在后台我将数据处理后存储在一个全局变量里,等 Ajax 请求成功后,再用 window.location.href = "" 去处理导出的操作,这样子浏览器就可以弹出下载框啦,下面呈上 Service 实现层的代码:

package com.gangdian.qc.service.impl;

@Service
public class LatestOrderServiceImpl implements LatestOrderService {

    @Autowired
    private LatestOrderDao latestOrderDao;

    List<LatestOrderInfos> exportMessage = new ArrayList<LatestOrderInfos>(); // 需要导出的信息

    @Override
    public Map<String, Object> getLatestOrder(MultipartFile file, HttpServletResponse response,
            HttpServletRequest request) {
        Map<String, Object> result = new HashMap<String, Object>(); // 返回的结果
        String dealResult = null;
        try {
            InputStream inputStream = file.getInputStream(); // 获取文件的输入流
            Integer length = file.getOriginalFilename().split("\\.").length; // 获取文件名数组的长度
            String suffix = file.getOriginalFilename().split("\\.")[length - 1]; // 取得文件后缀名
            if ("xls".equals(suffix)) {
                dealResult = hssfDeal(inputStream, result, response, request); // 如果后缀为.xls则用HSSFWorkbook
                result.put("message", dealResult);
            } else if ("xlsx".equals(suffix)) {
                dealResult = xssfDeal(file, result, response, request); // 后缀为.xlsx则用XSSFWorkbook
                result.put("message", dealResult);
            }
        } catch (Exception e) {
            result.put("message", "500!");
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return result;
    }

    /**
     * *.xlsx文件用XSSFWorkbook处理
     * 
     * @return
     */
    private String xssfDeal(MultipartFile file, Map<String, Object> result, HttpServletResponse response,
            HttpServletRequest request) throws IOException {
        String dealResult = null; // 返回的处理结果
        // 创建workbook对象,读取整个文档
        XSSFWorkbook workbook = new XSSFWorkbook(file.getInputStream());
        Sheet sheet = workbook.getSheetAt(0);
        // 获取sheet的最大row下标
        int lastRowNum = sheet.getLastRowNum();
        // 判断第一列标题是否包含 “物料代码”
        String title = sheet.getRow(0).getCell(0).getStringCellValue();
        if (title.indexOf("物料代码") < 0) {
            return "请注意,首列标题须为物料代码!";
        } else if (lastRowNum <= 0) {
            return "您导入的excel文件为空,请重新导入!";
        }
        for (Row row : sheet) {
            // 读取每一行的单元格
            Cell cell = row.getCell(0);
            if (cell != null) { // 单元格不为空
                cell.setCellType(Cell.CELL_TYPE_STRING); // 将该列单元格类型设置为String
                String materialCode = cell.getStringCellValue(); // 第一列数据
                if (materialCode != "" && materialCode.indexOf("物料代码") < 0) {
                    // 获取最新使用订单情况
                    LatestOrderInfos latestOrderInfos = latestOrderDao.getLatestOrderInfos(materialCode);
                    exportMessage.add(latestOrderInfos);
                }
            }
        }
        result.put("infos", exportMessage);
        return dealResult;
    }

    /**
     * *.xls文件用HSSFWorkbook处理
     * 
     * @return
     */
    private String hssfDeal(InputStream inputStream, Map<String, Object> result, HttpServletResponse response,
            HttpServletRequest request) throws IOException {
        String dealResult = null; // 返回的处理结果
        // 创建workbook对象,读取整个文档
        POIFSFileSystem poifsFileSystem = new POIFSFileSystem(inputStream);
        HSSFWorkbook wb = new HSSFWorkbook(poifsFileSystem);
        // 读取页脚sheet
        HSSFSheet sheetAt = wb.getSheetAt(0);
        // 判断第一列标题是否包含 “物料代码”
        String title = sheetAt.getRow(0).getCell(0).getStringCellValue();
        if (title.indexOf("物料代码") < 0) {
            return "首列标题须为物料代码!";
        }
        // 循环读取某一行
        for (Row row : sheetAt) {
            // 读取每一行的单元格
            Cell cell = row.getCell(0);
            if (cell != null) { // 单元格不为空
                String materialCode = cell.getStringCellValue(); // 第一列数据
                if (materialCode != "" && materialCode.indexOf("物料代码") < 0) {
                    // 获取最新使用订单情况
                    LatestOrderInfos latestOrderInfos = latestOrderDao.getLatestOrderInfos(materialCode);
                    exportMessage.add(latestOrderInfos);
                }
            }
        }
        result.put("infos", exportMessage);
        return dealResult;
    }

}

    2、当我导入的文件格式为 *.xlsx ,却用 HSSFWorkbook 去解析的时候,出现如下的错误

    org.apache.poi.poifs.filesystem.OfficeXmlFileException: The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (eg XSSF instead of HSSF)
直译:文件中的数据是用Office2007+XML保存的,而现在却调用OLE2 Office文档处理,应该使用POI不同的部分来处理这些数据,比如使用XSSF来代替HSSF

    因此,在这里,我们需要进行区分,*.xls 用 HSSFWorkbook 进行处理,而 *.xlsx 则用 XSSFWorkbook 处理,处理的前提需要导入以下的 jar 包。网上都有,懒得找可以问我要,我再附上链接,3.8-3.10版本的我都有。

前端系统嵌入grafana 前端导入_前端系统嵌入grafana

        3、在读取 Excel 中的数据时,报错java.lang.IllegalStateException: Cannot get a text value from a numeric cell

    大致意思就是不能从一个数值的列获取一个字符串类型的值。在代码中,我是通过 cell.getStringCellValue() 去获取单元格数据的,POI会判断单元格的类型,如果非字符串类型就会抛出上面的异常。

    解决方法:一个个的去 Excel 中将数值的单元格前面加上   ‘  ,变成字符串类型 ?这种方法太扯淡了。我们来看看比较便捷的,就是在获取值前加上以下语句,让服务器去帮你处理就可以啦,完美解决。

cell.setCellType(Cell.CELL_TYPE_STRING); // 将该列单元格类型设置为String

---------------------------------------

    最后放上导出 Excel 的代码:

@Override
    public void messageExport(HttpServletResponse response, HttpServletRequest request) {
        // 生成表格标题行
        String[] headers = { "物料代码", "最新使用单号", "最新出库日期", "最新入库日期" };
        // -----设置导出表格-----
        // 声明一个工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 生成一个表格
        HSSFSheet sheet = workbook.createSheet("物料最新使用订单情况");
        // 设置表格默认列宽度为15个字节
        sheet.setDefaultColumnWidth(15);
        sheet.autoSizeColumn(1, true);
        // 生成一个样式
        HSSFCellStyle style = workbook.createCellStyle();
        // 设置这些样式
        style.setAlignment(HSSFCellStyle.ALIGN_LEFT);
        style.setVerticalAlignment(org.apache.poi.ss.usermodel.CellStyle.VERTICAL_CENTER);
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        // 生成一个字体
        HSSFFont font = workbook.createFont();
        font.setFontHeightInPoints((short) 12);
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        // 把字体应用到当前的样式
        style.setFont(font);
        // 生成并设置另一个样式
        HSSFCellStyle style2 = workbook.createCellStyle();
        style2.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style2.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style2.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style2.setBorderTop(HSSFCellStyle.BORDER_THIN);
        // 生成另一个字体
        HSSFFont font2 = workbook.createFont();
        font2.setFontName("宋体");
        // 把字体应用到当前的样式
        style2.setFont(font2);
        // 产生表格标题行
        HSSFRow row = sheet.createRow(0);
        row.setHeightInPoints(30);
        for (int k = 0; k < headers.length; k++) {
            HSSFCell cell = row.createCell(k);
            cell.setCellStyle(style);
            HSSFRichTextString text = new HSSFRichTextString(headers[k]);
            cell.setCellValue(text);
        }
        // 写入数据,并设置样式
        for (LatestOrderInfos latestOrderInfos : exportMessage) {
            int lastRowNum = sheet.getLastRowNum() + 1;// 当前需要增加行的下标
            row = sheet.createRow(lastRowNum);
            row.setHeightInPoints(20);
            row.createCell(0).setCellValue(latestOrderInfos.getMaterialCode());
            row.createCell(1).setCellValue(latestOrderInfos.getLatestOrder());
            row.createCell(2).setCellValue(latestOrderInfos.getLatestOutDate());
            row.createCell(3).setCellValue(latestOrderInfos.getLatestInDate());
            for (int j = 0; j < headers.length; j++) {
                row.getCell(j).setCellStyle(style2);
            }
        }
        // 创建response输出流
        SimpleDateFormat df = new SimpleDateFormat("yyMMdd-HH.mm");// 设置日期格式
        String time = df.format(new Date());// new Date()为获取当前系统时间
        OutputStream os = null;
        try {
            os = response.getOutputStream();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        response.reset();
        String filename = "物料最新订单使用情况." + time + ".xls";
        response.setContentType("application/msexcel");
        try {
            // 设定输出文件头
            response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));
            // 定义输出类型
            response.setContentType("application/msexcel");
            // 写入文件
            workbook.write(os);
            exportMessage.clear();
            os.flush();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

三、知识拓展

拓展一:使用window.location.href同时导出多个文件

function downloadFiles(){
		  var files = [];
		  files.push("${ctx}/MyProject/storageDataExport1");
		  files.push("${ctx}/MyProject/storageDataExport2");
		  files.push("${ctx}/MyProject/storageDataExport3");
		  for(var ii=0; ii<files.length; ii++){
		    downloadURL(files[ii]);
		  }
		}
		var count=0;
		var downloadURL = function downloadURL(url){
		  var hiddenIFrameID = 'hiddenDownloader' + count++;
		  var iframe = document.createElement('iframe');
		  iframe.id = hiddenIFrameID;
		  iframe.style.display = 'none';
		  document.body.appendChild(iframe);
		  iframe.src = url;
		}

拓展二:使用隐藏form来执行导出操作

   当需要传一个很大数据到后台(window.location.href= actionUrl + "?" + data;),就会出问题了,当然,当数据量不大的时候,使用这种方式是极好的。导致这个问题的原因是各种浏览器对URL解析的长度限制是不同的。

  • Microsoft Internet Explorer (Browser):IE浏览器对URL的最大限制为2083个字符,如果超过这个数字,提交按钮没有任何反应。
  • Firefox (Browser):对于Firefox浏览器URL的长度限制为65,536个字符
  • Safari (Browser):URL最大长度限制为 80,000个字符。
  • Opera (Browser):URL最大长度限制为190,000个字符。
  • Google (chrome):url最大长度限制为8182个字符

     解决方法就换成了使用隐藏form来执行导出操作,如下:

<a href="javascript:void(0)" onclick="exportExcel()">导出1</a>

// 导出,使用这种方式 可以,使用 ajax请求不可以 导出excel
function exportExcel(){
     var form = $("<form>");
     form.attr('style', 'display:none');
     form.attr('target', '');
     form.attr('method', 'post');
     form.attr('action', '${pageContext.request.contextPath}/user/export');

     var input1 = $('<input>');
     input1.attr('type', 'hidden');
     input1.attr('name', 'data1');
     input1.attr('value', 'value1');  
     var input2 = $('<input>');
     input1.attr('type', 'hidden');
     input1.attr('name', 'data2');
     input1.attr('value', 'value2'); 
     ......//几个参数就放几个input,value可放很多类型(数组,字符,list,map等)

     $('body').append(form);//将表单放置在web中 
     form.append(input1);//将查询参数控件提交到表单上
     form.append(input2);
     ......
     
     form.submit();
     form.remove();    
}

拓展二来源:

拓展三:用iframe实现form表单提交不刷新页面

原理是form提交表单,设置target为iframe的name,iframe为隐藏,实现无刷新提交。

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="ctx" value="${pageContext.request.contextPath}" />

<script lang="text/javascript" src="js/jquery-1.10.2.min.js"></script>

<link rel="stylesheet" href="js/jquery-ui-1.10.3.custom.css" />
<script lang="text/javascript" src="js/jquery-ui-1.10.4.custom.js"></script>
<link rel="stylesheet" href="ext1/bms.css" />
<script type="text/javascript" src="js/bootstrap-tokenfield.js"></script>

<link rel="stylesheet" href="js/bootstrap.min.alco.css">
<link rel="stylesheet" href="js/css/bootstrap-tokenfield.alco.css"/>

<form method="post" action="${ctx}/exportServlet?action=1" enctype="multipart/form-data" name="bms927" target="if1">
<div>
	<table>
		<tr>
			<td>
				<select id="selects" name="selects" class="form-inq-control" >
				    <option value="SHIPPINGLABEL">SHIPPING Label</option>
				    <option value="SNLABEL">SN Label</option>
			</td>
			<td>
				<input  type="file" name="fileField" id="fileField" accept=".xls,.xlsx" class="form-control" style="margin-left: 10px"/> 
			</td>
			<td>
				<input type="submit" class="form-inq-btn" style="margin-left: 10px" value="<%=X10getMessage("LAB927.import")%>" />
			</td>
			<%-- <td>
				<input type="button" class="form-inq-btn" style="margin-left: 10px" value="转换导出Excel" onclick="submitForm()"/>
			</td> --%>
		</tr>
	</table>
</div> <br/> 
</form>


<iframe name="if1" style="display: none;"></iframe>


<%@include file="common/alco_footer.jsp"%>
package com.alco.bms.servlets;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.ibatis.session.SqlSession;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import com.alco.bms.mybatis.dao.BMS927Mapper;
import com.alco.bms.mybatis.entities.Bms927ImgInfos;
import com.alco.bms.mybatis.entities.BsmiLabelInfos;
import com.alco.bms.mybatis.entities.SNLabelInfos;
import com.alco.bms.mybatis.entities.ShippingLabelInfos;
import com.freestyle.common.db.mybatis.MybatisUtils;
import com.freestyle.utils.ArrayUtil;
/****
 * Export Servlet 
 * @author dgmislrh
 * 2018年11月12日
 */
public class ExportServlet extends HttpServlet {
	/**
	* 
	*/
	private static final long serialVersionUID = -1879826989713327690L;

	
   @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       doGet(req, resp);
    }
	   
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	    String action = req.getParameter("action");
	    if ("1".equals(action)) {
	        labelExport(req, resp);
        }
	} 

    /**
     * @param req
     * @param resp
     * @throws IOException
     * @throws UnsupportedEncodingException
     */
    private void labelExport(HttpServletRequest req, HttpServletResponse resp)
            throws IOException, UnsupportedEncodingException {
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);//form表单上传的资料
        SimpleDateFormat df = new SimpleDateFormat("yyMMddHHmm");// 设置日期格式
        String time = df.format(new Date());// new Date()为获取当前系统时间
        //获取From表单提交的data
        List<String> snList =  new ArrayList<String>();
        String type= null;//转换的类型
        try {
         List items = upload.parseRequest(req);
         Iterator itr = items.iterator();
         while (itr.hasNext()) {
             FileItem item = (FileItem) itr.next();
             if (item.isFormField() && "selects".equals(item.getFieldName()) ) {
                 type = item.getString("UTF-8");
                 //System.out.println("表单参数名:" + item.getFieldName() + ",表单参数值:" + item.getString("UTF-8"));
             } else if(!item.isFormField()) {
             if (item.getName() != null && !item.getName().equals("")) {
                 //System.out.println("上传文件的大小:" + (item.getSize()/1024)+"KB");
                 //System.out.println("上传文件的类型:" + item.getContentType());
                 //System.out.println("上传文件的名称:" + item.getName());
                 snList = readSnExcel(item.getInputStream());
              }
            }
         }
         if (snList==null || snList.size()<=0) {
            return;
        }
        }catch (Exception e) {
            e.printStackTrace();
        }
	    //System.err.println("type=="+type);
	    ServletOutputStream sos = resp.getOutputStream();
	    ZipOutputStream zipOutputStream= new ZipOutputStream(sos);
	    // 生成表格标题行
	    String[] headers = null;
	    List<String> strsToList1 = null;
        String[] strsStrings = new String[]{"SN","Itemattribute1","Itemattribute2","Itemattribute3","Itemattribute4","Itemattribute5","Itemattribute6","Itemattribute7","Itemattribute8"};
        strsToList1= Arrays.asList(strsStrings);
        headers = (String[]) strsToList1.toArray(new String[strsToList1.size()]);
        String zipname=type+"-"+time+".zip";
        resp.reset();
        resp.setContentType("application/x-download"); 
        resp.setHeader("Content-Disposition", "attachment;filename="+ new String((zipname).getBytes(), "iso-8859-1"));
        Map<String, List<ShippingLabelInfos>> listMap = getShipData(snList,zipOutputStream,type,time);
        for (String key:listMap.keySet()){
            System.out.println("key=="+key);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            List<ShippingLabelInfos> list = listMap.get(key);
            if (!"error".equals(key)) {
                exportShipExcel(type, headers, list, baos);
            }else {
                //去掉无数据的信息
            }
            compressFileToZipStream(zipOutputStream, baos, "data/"+type+"-"+key+"-"+time+".xls");
            baos.close();
                
        }
	    zipOutputStream.flush();
        zipOutputStream.close();
        sos .close();
    }


    /**
     * @param workbook
     * @return
     */
    @SuppressWarnings("deprecation")
    private HSSFCellStyle setContentStyle(HSSFWorkbook workbook) {
        HSSFCellStyle style2 = workbook.createCellStyle();
        style2.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style2.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style2.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style2.setBorderTop(HSSFCellStyle.BORDER_THIN);
        // 生成另一个字体
        HSSFFont font2 = workbook.createFont();
        font2.setFontName("宋体");
        // 把字体应用到当前的样式
        style2.setFont(font2);
        return style2;
    }

    /**
     * @param workbook
     * @return
     */
    @SuppressWarnings("deprecation")
    private HSSFCellStyle setHeaderStyle(HSSFWorkbook workbook) {
        HSSFCellStyle style = workbook.createCellStyle();
        // 设置这些样式
        style.setAlignment(HSSFCellStyle.ALIGN_LEFT);
        style.setVerticalAlignment(org.apache.poi.ss.usermodel.CellStyle.VERTICAL_CENTER);
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        // 生成一个字体
        HSSFFont font = workbook.createFont();
        font.setFontHeightInPoints((short) 12);
        font.setFontName("宋体");
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        // 把字体应用到当前的样式
        style.setFont(font);
        return style;
    }

    private Map<String, List<ShippingLabelInfos>> getShipData(List<String> snList, ZipOutputStream zipOutputStream, String type, String time) {
        SqlSession lvSess=MybatisUtils.getSession();
        List<ShippingLabelInfos> shipLabelInfos = new ArrayList<ShippingLabelInfos>();
        List<ShippingLabelInfos> errShipLabelInfos = new ArrayList<ShippingLabelInfos>();
        try{
            BMS927Mapper bms927Mapper=lvSess.getMapper(BMS927Mapper.class);
            List<List<String>> ssList=ArrayUtil.subListByCount(snList, 20);
            for (List<String>list:ssList) {
                bms927Mapper.createSNTable();                
                for (String sn:list) {
                    bms927Mapper.insertSN(sn);
                }
                shipLabelInfos.addAll(bms927Mapper.queryShipData());
            }
            for(ShippingLabelInfos sl:shipLabelInfos) {
                if (sl.getTemplateSize()==null) sl.setTemplateSize("NoSize");
                Iterator<String> it = snList.iterator();
                while(it.hasNext()){
                    String sn = it.next();
                    if(sn.equals(sl.getSn())){
                        it.remove();//剔除有数据的sn
                    }
                }
            }
            Map<String, List<ShippingLabelInfos>> listMap = shipLabelInfos.stream().collect(Collectors.groupingBy(t -> t.getTemplateSize()));
            if (snList!=null && snList.size()>0) {
                for(String sn:snList) {
                    errShipLabelInfos.add(new ShippingLabelInfos(sn));
                }
                if (errShipLabelInfos!=null && errShipLabelInfos.size()>0) {
                    listMap.put("error", errShipLabelInfos);
                }
            }
            return listMap;
        }catch (Exception e) {
            lvSess.rollback();
            e.printStackTrace();
        }
        finally{
            MybatisUtils.closeSession(lvSess);
        }
        return null;
    }
    
    public void exportShipExcel(String type, String[] headers,List<ShippingLabelInfos> shipListInfos, OutputStream out) {
        // -----设置导出表格-----
        // 声明一个工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 生成一个表格
        HSSFSheet sheet = workbook.createSheet(type);
        // 设置表格默认列宽度为20个字节
        sheet.setDefaultColumnWidth(20);
        sheet.autoSizeColumn(1, true);
        //设置行高
        HSSFRow row = sheet.createRow(0);
        row.setHeightInPoints(30);
        // 生成一个样式
        HSSFCellStyle headersStyle = setHeaderStyle(workbook);
        // 生成并设置另一个样式
        HSSFCellStyle contentStyle = setContentStyle(workbook);
        for (int k = 0; k < headers.length; k++) {
            HSSFCell cell = row.createCell(k);
            cell.setCellStyle(headersStyle);
            HSSFRichTextString text = new HSSFRichTextString(headers[k]);
            cell.setCellValue(text);
        }
     // 写入数据,并设置样式
        for (ShippingLabelInfos labelInfos: shipListInfos) {
            int lastRowNum = sheet.getLastRowNum() + 1;// 当前需要增加行的下标
            row = sheet.createRow(lastRowNum);
            row.setHeightInPoints(20);
            row.createCell(0).setCellValue(labelInfos.getSn());
            row.createCell(1).setCellValue(labelInfos.getItemattribute1());
            row.createCell(2).setCellValue(labelInfos.getItemattribute2());
            row.createCell(3).setCellValue(labelInfos.getItemattribute3());
            row.createCell(4).setCellValue(labelInfos.getItemattribute4());
            row.createCell(5).setCellValue(labelInfos.getItemattribute5());
            row.createCell(6).setCellValue(labelInfos.getItemattribute6());
            row.createCell(7).setCellValue(labelInfos.getItemattribute7());
            row.createCell(8).setCellValue(labelInfos.getItemattribute8());
            for (int j = 0; j < headers.length; j++) {
                row.getCell(j).setCellStyle(contentStyle);
            }
        }
        try {
            workbook.write(out);
            workbook.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    
    public static void compressFileToZipStream(ZipOutputStream zipOutputStream, 
            ByteArrayOutputStream excelOutputStream,String fileName) {
        byte[] buf = new byte[1024];
        try {
            // Compress the files
            byte[] content = excelOutputStream.toByteArray();
            ByteArrayInputStream is = new ByteArrayInputStream(content);
            BufferedInputStream bis = new BufferedInputStream(is);
            // Add ZIP entry to output stream.
            zipOutputStream.putNextEntry(new ZipEntry(fileName));
            // Transfer bytes from the file to the ZIP file
            int len;
            while ((len = bis.read(buf)) > 0) {
                zipOutputStream.write(buf, 0, len);
            }
            // Complete the entry
            zipOutputStream.closeEntry();
            bis.close();
            is.close();
            // Complete the ZIP file
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
 // 读取Office 2007excel 
    public static List<String> readSnExcel(InputStream fileInputStream) throws Exception 
    { 
        List<String> list = new LinkedList<String>(); 
        // 构造XSSFWorkbook对象,strPath传入文件路径 
        XSSFWorkbook xwb = new XSSFWorkbook(fileInputStream); 
        // 读取第一张表格的内容 
        XSSFSheet sheet = xwb.getSheetAt(0); 
        String value = null; 
        XSSFRow row = null; 
        XSSFCell cell = null; 
        //System.out.println("读取2007excel内容如下:"); 
        for (int i = sheet.getFirstRowNum(); i < sheet.getPhysicalNumberOfRows(); i++) 
        { 
            row = sheet.getRow(i); 
            if (i == 0 || row == null) 
            { 
                continue; 
            } 
            cell = row.getCell(0); 
            if (cell == null || cell.toString() == "") continue; 
            DecimalFormat df = new DecimalFormat("0");// 格式化 number string 
            switch (cell.getCellType()) 
            { 
            case XSSFCell.CELL_TYPE_STRING: 
                value = cell.getStringCellValue(); 
                //System.out.println(" " + value + " "); 
                break; 
            case XSSFCell.CELL_TYPE_NUMERIC: 
                value = df.format(cell.getNumericCellValue()); 
                //System.out.println(" " + value + " "); 
                break; 
            case XSSFCell.CELL_TYPE_BLANK: 
                value = ""; 
                //System.out.println(value); 
                break; 
            default: 
                value = cell.toString(); 
                //System.out.println(" " + value + " "); 
                break; 
            } 
            if (value == null || "".equals(value)) 
            { 
                continue; 
            } 
            list.add(value); 
        } 
        return list; 
    } 

}