spring mvc的excel报表文件下载时流的冲突解决

在jsp或者在servlet中有时要用到 response.getOutputStream(),但是此时会在后台报这个错误java.lang.IllegalStateException: getOutputStream() has already been called for this respons,这问题困扰了我好久都没解决,最近这个项目中我又遇到了,下定决心一定要解决掉,最后终于让我给找到解决的方法了,这个异常时因为 response.getOutputStream()跟response.getWriter()相冲突造成的,呵呵!现在记录下,发出来和大家共享 下,希望能帮到遇到同样问题的朋友们,解决方法如下:

    out.clearBuffer(); 

    out = pageContext.pushBody();

在调用response.getOutputStream()之前加上上面两代码,就ok了!

 

上面的是网上流行的解决方案, 在jsp中<% %>写入红色代码;

 

我的解决方案是将改下载方法的返回值为void或return时为null都可以, 我是用的是spring mvc 在Struts中的方法通常也会带有返回值;

code:

 

package com.piaomeng.b2bv5.stat.controller;

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.List;
import java.util.Map;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

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.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.piaomeng.b2bv5.core.auth.AuthPassport;
import com.piaomeng.b2bv5.stat.service.IBStatisticsService;
import com.piaomeng.b2bv5.stat.vo.PasteCount;
import com.piaomeng.b2bv5.stat.vo.PasteCountExcel;
import com.piaomeng.b2bv5.util.PrintWriterUtil;

@Controller
@Scope("prototype")
@RequestMapping("/statistics")
public class StickPointController {
    @Autowired
    private IBStatisticsService statisticsService;
    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    
    /**销售跳转链接*/
    @RequestMapping("/skipTieDianXsIndex")
    @AuthPassport(auth="/statistics/skipTieDianXsIndex", check=false)
    public String skipTieDianXsIndex(Map<String,Object> map){
        map.put("beginDate", sdf.format(new Date()));
        map.put("endDate", sdf.format(new Date()));
        return "/jsp/stat/stickPointStatistics_xs";
    }
    /**销售显示主要方法*/
    @RequestMapping("/selectTieDianXsList")
    @AuthPassport(auth="/statistics/selectTieDianXsList", check=false)
    public String selectTieDianXsList(HashMap<String,Object> map, String salesId,
            String beginDate, String endDate){
        map.put("beginDate", beginDate);
        map.put("endDate", endDate);
        map.put("salesId", salesId);
        // 根据日期判断是上半年/下半年分别查询, 例如2015-09-03 只截取月 09;
        String currentMonth = beginDate.substring(5, 7);// 开始日期和结束日期的月份相同, 页面js已经校验;
        String[] first_half_year = {"01", "02", "03", "04", "05", "06"};
        String[] last_half_year = {"07", "08", "09", "10", "11", "12"};
        List<String> fhy = Arrays.asList(first_half_year);
        List<String> lhy = Arrays.asList(last_half_year);
        
        // 设置动态表名 1-6 月 t_od_border1501 7-12 月 t_od_border1507; 上半年设置表后缀为01 (1-6月)下半年设置表后缀为07 (7-12月);
        String tableName = null;
        if (fhy.contains(currentMonth)) {// 上半年;
            tableName = "T_OD_BORDER" + beginDate.substring(2, 4) + "01";
        }
        if (lhy.contains(currentMonth)) {// 下半年;
            tableName = "T_OD_BORDER" + beginDate.substring(2, 4) + "07";
        }
        map.put("border", tableName);
        map.put("orderdesc", "T_OD_ORDERDESC".concat(beginDate.substring(2, 4)).concat(currentMonth));
        map.put("passinfo", "T_OD_PASSINFO".concat(beginDate.substring(2, 4)).concat(currentMonth));
        List<PasteCount> pasteCounts = statisticsService
                .selectPasteCountList(map);
        // 计算总计;
        PasteCount pc = null;
        int ticketCount = 0;
        double buyPrice = 0.00, levelPrice = 0.00;
        if (pasteCounts.size() > 0 && pasteCounts != null) {
            for (Iterator<PasteCount> iterator = pasteCounts.iterator(); iterator.hasNext();) {
                PasteCount item = iterator.next();
                ticketCount += item.getTicketCount();
                buyPrice += item.getBuyPrice();
                levelPrice += item.getLevelPrice();
            }
            pc = new PasteCount();
            pc.setUsername("全部");
            pc.setTicketCount(ticketCount);
            pc.setBuyPrice(buyPrice);
            pc.setLevelPrice(levelPrice);
        }
        // end
        map.put("pasteCounts", pasteCounts);
        map.put("totalCount", pc);
        return "/jsp/stat/stickPointStatistics_xs";
    }
    /**销售的下载贴点明细statistics/selectTieDianXsListDownload*/
    @RequestMapping("/selectTieDianXsListDownload")
    @AuthPassport(auth="/statistics/selectTieDianXsListDownload", check=false)
    public String selectTieDianXsListDownload(HashMap<String,Object> map, String salesId,
            String beginDate, String endDate, HttpServletResponse response){
        try {
            map.put("beginDate", beginDate);
            map.put("endDate", endDate);
            map.put("salesId", salesId);
            // 根据日期判断是上半年/下半年分别查询, 例如2015-09-03 只截取月 09;
            String currentMonth = beginDate.substring(5, 7);// 开始日期和结束日期的月份相同, 页面js已经校验;
            String[] first_half_year = {"01", "02", "03", "04", "05", "06"};
            String[] last_half_year = {"07", "08", "09", "10", "11", "12"};
            List<String> fhy = Arrays.asList(first_half_year);
            List<String> lhy = Arrays.asList(last_half_year);
            
            // 设置动态表名 1-6 月 t_od_border1501 7-12 月 t_od_border1507; 上半年设置表后缀为01 (1-6月)下半年设置表后缀为07 (7-12月);
            String tableName = null;
            if (fhy.contains(currentMonth)) {// 上半年;
                tableName = "T_OD_BORDER" + beginDate.substring(2, 4) + "01";
            }
            if (lhy.contains(currentMonth)) {// 下半年;
                tableName = "T_OD_BORDER" + beginDate.substring(2, 4) + "07";
            }
            map.put("border", tableName);
            map.put("orderdesc", "T_OD_ORDERDESC".concat(beginDate.substring(2, 4)).concat(currentMonth));
            map.put("passinfo", "T_OD_PASSINFO".concat(beginDate.substring(2, 4)).concat(currentMonth));
            List<PasteCountExcel> pasteCountExcels = statisticsService
                    .selectTieDianXsListDownload(map);
            if (pasteCountExcels.size() > 0 && pasteCountExcels != null) {// 如果数据不为空则写入Excel文件后下载;
                // 导出数据到报表;
                exportTdmxXs(selectListHeaderXs(), pasteCountExcels, response);
            }else{// 如果数据为空则不进行下载直接显示页面提示信息;
                map.put("tips", "当前数据为空!");
                return "/jsp/stat/stickPointStatistics_xs";
            }
        } catch (Exception e) {
            PrintWriterUtil.writeToClient(response, "下载失败!");
            e.printStackTrace();
        }
        return null;
    }
    
    //销售报表贴点具体方法;
    public static void exportTdmxXs(List<String> headers, List<PasteCountExcel> contents, HttpServletResponse response){
        try {
            if (contents != null && contents.size() > 0) {
                String xlsFile = "tdmx_xs" + new SimpleDateFormat("yyyyMMddHHssmm") + ".xls";
                HSSFWorkbook wb = new HSSFWorkbook();
                HSSFSheet sheet = wb.createSheet("销售贴点明细");

                HSSFRow nRow = null;
                HSSFCell nCell   = null;
                
                // 表头
                nRow = sheet.createRow(0);// 表头(共一行);
                for(int i = 0; i < headers.size(); i++){// 共?列; 日期, 采购ID, 所属人, 所属城市, 级别贴点订单票数, 级别贴点金额;
                    // 为列 创建单元格对象
                    nCell = nRow.createCell(i);
                    // 为列 创建单元格对象设置内容
                    nCell.setCellValue(headers.get(i));
                    /** 为表头每个列设置颜色*/
                    HSSFCellStyle curStyle = wb.createCellStyle();
                    //curStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);// 单元格内容居中对齐
                    curStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
                    curStyle.setFillForegroundColor((short) 10);
                    //********
                    curStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);//粗实线
                    curStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
                    curStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
                    curStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
                    // 设置字体;
                    HSSFFont curFont = wb.createFont();                                //设置字体
                    curFont.setFontName("微软雅黑");                                    //设置英文字体
                    curFont.setCharSet(HSSFFont.DEFAULT_CHARSET);                    //设置中文字体,那必须还要再对单元格进行编码设置
                    curFont.setFontHeightInPoints((short)12);                        //字体大小
                    curFont.setBoldweight((short)5);
                    curStyle.setFont(curFont);
                    //********
                    nCell.setCellStyle(curStyle);
                    /**end*/
                }
                // 表内容
                for (int i = 0; i < contents.size(); i++) {
                    nRow = sheet.createRow(i+1);    // 表内容(动态行);
                    for(int j = 0; j < headers.size(); j++){// 共?列; 日期, 采购ID, 所属人, 所属城市, 级别贴点订单票数, 级别贴点金额;
                        // 为列 创建单元格对象
                        nCell = nRow.createCell(j);
                        // 为列 创建单元格对象设置内容
                        if ("日期".equals(headers.get(j))) {
                            sheet.setColumnWidth(j, 3000);
                            nCell.setCellValue(contents.get(i).getLastUpdateTime());
                        }else if ("采购ID".equals(headers.get(j))) {
                            nCell.setCellValue(contents.get(i).getBuyerId());
                        }else if ("所属人".equals(headers.get(j))) {
                            nCell.setCellValue(contents.get(i).getUsername());
                        }else if ("所属城市".equals(headers.get(j))) {
                            sheet.setColumnWidth(j, 3000);
                            nCell.setCellValue(contents.get(i).getBuyerCity());
                        }else if ("级别贴点订单票数".equals(headers.get(j))) {
                            sheet.setColumnWidth(j, 5000);
                            nCell.setCellValue(contents.get(i).getTicketCount());
                        }else if ("级别贴点金额".equals(headers.get(j))) {
                            sheet.setColumnWidth(j, 4000);
                            nCell.setCellValue(contents.get(i).getLevelPrice());
                        }
                        // 为该列设置背景色 start
                        HSSFCellStyle curStyle = wb.createCellStyle();
                        curStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);// 单元格内容居中对齐
                        curStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
                        curStyle.setFillForegroundColor((short) 40);
                        //********
                        curStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
                        curStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
                        curStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
                        curStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
                        //********
                        nCell.setCellStyle(curStyle);
                        // end
                    }
                }
                
                //设置样式
                //nCell.setCellStyle(leftStyle(wb));

                // 准备下载;
                response.reset();
                response.addHeader("Content-Disposition", "attachment;filename=" + xlsFile);
                response.setContentType("application/octet-stream");// .*( 二进制流,不知道下载文件类型), 不知道下载的类型具体是什么可以使用这个;
                //response.setContentType("application/vnd.ms-excel");// 定义输出类型
                
                ServletOutputStream sos = response.getOutputStream();
                wb.write(sos);
                sos.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static List<String> selectListHeaderXs(){
        //日期, 采购ID, 所属人, 所属城市, 级别贴点订单票数, 级别贴点金额;
        List<String> lists = new ArrayList<String>();
        lists.add("日期");
        lists.add("采购ID");
        lists.add("所属人");
        lists.add("所属城市");
        lists.add("级别贴点订单票数");
        lists.add("级别贴点金额");
        return lists;
    }
    
}

 

点击下载时控制台不会报错:

  java.lang.IllegalStateException: getOutputStream() has already been called for this response

没报错吧!:-D:)

完成;

 

 

原文地址:https://www.cnblogs.com/YingYue/p/4861681.html