使用POI操作excel打印报表

以前做过类似物流的系统,将报表打印部分做一个小小梳理,以后可复用

一:POI简介

POI是Java编写的可以提供对office的操作,是“Poor Obfuscation Implementation”的首字母缩写,意为“简洁版的模糊实现”。

1:包结构

HSSF提供读写Microsoft Excel XLS格式档案的功能。

XSSF提供读写Microsoft Excel OOXML XLSX格式档案的功能。

HWPF提供读写Microsoft Word DOC格式档案的功能。

HSLF提供读写Microsoft PowerPoint格式档案的功能。

HDGF提供读Microsoft Visio格式档案的功能。

HPBF提供读Microsoft Publisher格式档案的功能。

HSMF提供读Microsoft Outlook格式档案的功能。

2:常用类与方法说明

二:程序书写打印报表

打印报表只需两步:一获取要打印的数据,二将数据写入到excel中

以打印公司联系人通讯录为例:

1:打印公司通信录(主要步骤)

              /*

               * 操作步骤:

               * 1、获取数据

               * 2、将数据写入到excel文件中

               */

public void print() throws FileNotFoundException, IOException{

              //设置查询条件

              Factory factory = new Factory();

              //只查询没禁用的

              factory.setState(1);

              //第一步:获取数据

              List<Factory> dataList = factoryService.find(factory);

              String[] title = new String[]{"厂家全称","缩写","联系人","电话","手机","传真","备注"};

             

              //第二步

              //创建工作簿,使用HSSF

              Workbook wb = new HSSFWorkbook();

              //创建工作表

              Sheet sheet = wb.createSheet();

              int rowNo = 0;                                                                     //行号,以便于复用

              int colNo = 0;                                                               //列号

              Row nRow = null;

              Cell nCell = null;

             

              sheet.setColumnWidth(0, 30*256);                                //设置列宽

              //创建行对象,起始行为rowNo

              nRow = sheet.createRow(rowNo);

    //

              nRow.setHeightInPoints(40);

    //合并单元格,新对象,不会覆盖合并的那些单元格,只是遮住,从rowNo行到rowNo行,从第0列到第六列 进行合并

              sheet.addMergedRegion(new CellRangeAddress(rowNo, rowNo, 0, 6));                    

              rowNo++;

             

              //创建单元格(列)依附在行上的

              nCell = nRow.createCell(0);

              //设置单元格内容

              nCell.setCellValue("生产厂家通讯录");

              //设置大标题样式

              nCell.setCellStyle(this.bigTilteStyle(wb));        

              //写标题

              nRow = sheet.createRow(rowNo++);

              nRow.setHeightInPoints(28);                                                //设置行高         

                

              for(int i=0;i<title.length;i++){

                     nCell = nRow.createCell(i);

                     nCell.setCellValue(title[i]);

                     nCell.setCellStyle(this.titleStyle(wb));         //绑定样式

              }

             

              //写数据

              for(int j=0;j<dataList.size();j++){

                     colNo = 0;                                                      //初始化

                     Factory f = dataList.get(j);                                //获取到每条厂家记录

                    

                     nRow = sheet.createRow(rowNo++);

                     nRow.setHeightInPoints(21);

                    

                     nCell = nRow.createCell(colNo++);

                     nCell.setCellValue(f.getFullName());

                     nCell.setCellStyle(this.textStyle(wb));

                    

                     nCell = nRow.createCell(colNo++);

                     nCell.setCellValue(f.getFactoryName());

                     nCell.setCellStyle(this.textStyle(wb));

                    

                     nCell = nRow.createCell(colNo++);

                     nCell.setCellValue(f.getContractor());

                     nCell.setCellStyle(this.textStyle(wb));

                    

                     nCell = nRow.createCell(colNo++);

                     nCell.setCellValue(f.getPhone());

                     nCell.setCellStyle(this.textStyle(wb));

                    

                     nCell = nRow.createCell(colNo++);

                     nCell.setCellValue(f.getMobile());

                     nCell.setCellStyle(this.textStyle(wb));

                    

                     nCell = nRow.createCell(colNo++);

                     nCell.setCellValue(f.getFax());

                     nCell.setCellStyle(this.textStyle(wb));

                    

                     nCell = nRow.createCell(colNo++);

                     nCell.setCellValue(f.getCnote());

                     nCell.setCellStyle(this.textStyle(wb));

              }

              //文件输出流

              FileOutputStream os = new FileOutputStream("c:\factory.xls");                  //输出流

              wb.write(os);                                            //写入到文件中

              os.flush();                                                        //清空缓存

              os.close();                                                       //关闭

       }

2:设置单元格样式

  //大标题样式

       private CellStyle bigTilteStyle(Workbook wb){

              //创建一个单元格样式对象

              CellStyle curStyle = wb.createCellStyle();

              curStyle.setAlignment(CellStyle.ALIGN_CENTER);                                       //横向居中

              curStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);                //纵向居中

             

              Font curFont = wb.createFont();                                                                //创建字体对象

              curFont.setFontName("华文隶书");                                                                   //设置字体

              curFont.setFontHeightInPoints((short)30);                                           //设置字体大小

              curStyle.setFont(curFont);                                                                          //将字体对象绑定到样式对象上 

              return curStyle;

       }

      

       //标题样式

       private CellStyle titleStyle(Workbook wb){

              //创建一个单元格样式对象

              CellStyle curStyle = wb.createCellStyle();

              curStyle.setAlignment(CellStyle.ALIGN_CENTER);                                       //横向居中

              curStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);                //纵向居中

             

              Font curFont = wb.createFont();                                                                //创建字体对象

              curFont.setFontName("微软雅黑");                                                                   //设置字体

              curFont.setFontHeightInPoints((short)12);                                           //设置字体大小       

              curStyle.setFont(curFont);                                                                          //将字体对象绑定到样式对象上

              //画线

              curStyle.setBorderTop(CellStyle.BORDER_THIN);                                        //细实线

              curStyle.setBorderBottom(CellStyle.BORDER_THIN);

              curStyle.setBorderLeft(CellStyle.BORDER_THIN);

              curStyle.setBorderRight(CellStyle.BORDER_THIN);

              return curStyle;

       }

       //文本样式

       private CellStyle textStyle(Workbook wb){

              //创建单元格样式

              CellStyle xStyle = wb.createCellStyle();

              //创建字体样式

              Font xFont = wb.createFont();

              xStyle.setFont(xFont);

              //垂直居中

              xStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);                   //纵向居中

              //画线

              xStyle.setBorderTop(CellStyle.BORDER_THIN);                                    //细实线

              xStyle.setBorderBottom(CellStyle.BORDER_THIN);

              xStyle.setBorderLeft(CellStyle.BORDER_THIN);

              xStyle.setBorderRight(CellStyle.BORDER_THIN);

              return xStyle;

       }

POI处理列宽时有BUG,列宽精度不够。

3:产生临时的excel存放在临时文件夹下

              String path = request.getSession().getServletContext().getRealPath("/");            //虚拟路径对应的真实物理路径

              path += "/tmpfile";                           //防止tomcat8不能直接获取.getRealPath("/tmpfile")会为null

              File file = new File(path);

              if(!file.exists()){

                     file.mkdirs();                        //创建多级目录

              }

4:文件重命名防止并发打印冲突

              FileUtil fu = new FileUtil();

              String fileName = path + "/" + fu.newFile(path, "factory.xls");              //产生新的文件名,防止冲突

工具类方法

       /* 目录下已经有同名文件,则文件重命名,增加文件序号*/

       public String newFile(String sPath, String sFile){

              String newFileName = new String();

              String withoutExt = new String();

              File curFile = new File(sPath + "\" + sFile);

              if (curFile.exists()) {

                     for(int counter = 1; curFile.exists(); counter++){

                            withoutExt = this.getNameWithoutExtension(curFile.getName());

                            if(withoutExt.endsWith(counter-1 + ")")){

                                   withoutExt = withoutExt.substring(0,withoutExt.indexOf("("));        //idea

                            }

                newFileName = withoutExt + "(" + counter + ")" + "." + getFileExt(curFile.getName());

                curFile = new File(sPath + "\" + newFileName);

            }

              }else{

                     newFileName = curFile.getName();

              }

              return newFileName;

       }

5:用户下载打印的报表

用户下载有两种方法:

1) 有临时文件,给下载传下载文件,页面就可以下载

2) 直接写入到response中

    //生成流对象

              ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();              

              wb.write(byteArrayOutputStream);

             

              DownloadUtil du = new DownloadUtil();

              //du.prototypeDownload(file, returnName, response, delFlag)                           //下载临时文件,下载后删除

              du.download(byteArrayOutputStream, response, "货物订单.xls");        //弹出下载框,用户就可以直接下载

Download工具类

  1 import java.io.ByteArrayOutputStream;
  2 
  3 import java.io.File;
  4 
  5 import java.io.FileInputStream;
  6 
  7 import java.io.IOException;
  8 
  9  
 10 
 11 import javax.servlet.ServletOutputStream;
 12 
 13 import javax.servlet.http.HttpServletResponse;
 14 
 15  
 16 
 17 public class DownloadUtil {
 18 
 19       
 20 
 21        /**
 22 
 23         * @param filePath 要下载的文件路径
 24 
 25         * @param returnName 返回的文件名
 26 
 27         * @param response HttpServletResponse
 28 
 29         * @param delFlag 是否删除文件
 30 
 31         */
 32 
 33        protected void download(String filePath,String returnName,HttpServletResponse response,boolean delFlag){
 34 
 35               this.prototypeDownload(new File(filePath), returnName, response, delFlag);
 36 
 37        }
 38 
 39  
 40 
 41  
 42 
 43        /**
 44 
 45         * @param file 要下载的文件
 46 
 47         * @param returnName 返回的文件名
 48 
 49         * @param response HttpServletResponse
 50 
 51         * @param delFlag 是否删除文件
 52 
 53         */
 54 
 55        protected void download(File file,String returnName,HttpServletResponse response,boolean delFlag){
 56 
 57               this.prototypeDownload(file, returnName, response, delFlag);
 58 
 59        }
 60 
 61       
 62 
 63        /**
 64 
 65         * @param file 要下载的文件
 66 
 67         * @param returnName 返回的文件名
 68 
 69         * @param response HttpServletResponse
 70 
 71         * @param delFlag 是否删除文件
 72 
 73         */
 74 
 75        public void prototypeDownload(File file,String returnName,HttpServletResponse response,boolean delFlag){
 76 
 77               // 下载文件
 78 
 79               FileInputStream inputStream = null;
 80 
 81               ServletOutputStream outputStream = null;
 82 
 83               try {
 84 
 85                      if(!file.exists()) return;
 86 
 87                      response.reset();
 88 
 89                      //设置响应类型    PDF文件为"application/pdf",WORD文件为:"application/msword", EXCEL文件为:"application/vnd.ms-excel"。 
 90 
 91                      response.setContentType("application/octet-stream;charset=utf-8");
 92 
 93  
 94 
 95                      //设置响应的文件名称,并转换成中文编码
 96 
 97                      //returnName = URLEncoder.encode(returnName,"UTF-8");
 98 
 99                      returnName = response.encodeURL(new String(returnName.getBytes(),"iso8859-1"));    //保存的文件名,必须和页面编码一致,否则乱码
100 
101                     
102 
103                      //attachment作为附件下载;inline客户端机器有安装匹配程序,则直接打开;注意改变配置,清除缓存,否则可能不能看到效果
104 
105                      response.addHeader("Content-Disposition",   "attachment;filename="+returnName); 
106 
107                     
108 
109                      //将文件读入响应流
110 
111                      inputStream = new FileInputStream(file);
112 
113                      outputStream = response.getOutputStream();
114 
115                      int length = 1024;
116 
117                      int readLength=0;
118 
119                      byte buf[] = new byte[1024];
120 
121                      readLength = inputStream.read(buf, 0, length);
122 
123                      while (readLength != -1) {
124 
125                             outputStream.write(buf, 0, readLength);
126 
127                             readLength = inputStream.read(buf, 0, length);
128 
129                      }
130 
131               } catch (Exception e) {
132 
133                      e.printStackTrace();
134 
135               } finally {
136 
137                      try {
138 
139                             outputStream.flush();
140 
141                      } catch (IOException e) {
142 
143                             e.printStackTrace();
144 
145                      }
146 
147                      try {
148 
149                             outputStream.close();
150 
151                      } catch (IOException e) {
152 
153                             e.printStackTrace();
154 
155                      }
156 
157                      try {
158 
159                             inputStream.close();
160 
161                      } catch (IOException e) {
162 
163                             e.printStackTrace();
164 
165                      }
166 
167                      //删除原文件
168 
169                     
170 
171                      if(delFlag) {                        
172 
173                             file.delete();
174 
175                      }
176 
177               }
178 
179        }
180 
181  
182 
183        /**
184 
185         * @param byteArrayOutputStream 将文件内容写入ByteArrayOutputStream
186 
187         * @param response HttpServletResponse      写入response
188 
189         * @param returnName 返回的文件名
190 
191         */
192 
193        public void download(ByteArrayOutputStream byteArrayOutputStream, HttpServletResponse response, String returnName) throws IOException{
194 
195               response.setContentType("application/octet-stream;charset=utf-8");
196 
197               returnName = response.encodeURL(new String(returnName.getBytes(),"iso8859-1"));               //保存的文件名,必须和页面编码一致,否则乱码
198 
199               response.addHeader("Content-Disposition",   "attachment;filename=" + returnName); 
200 
201               response.setContentLength(byteArrayOutputStream.size());
202 
203              
204 
205               ServletOutputStream outputstream = response.getOutputStream();    //取得输出流
206 
207               byteArrayOutputStream.writeTo(outputstream);                                 //写到输出流
208 
209               byteArrayOutputStream.close();                                                         //关闭
210 
211               outputstream.flush();                                                                         //刷数据
212 
213        }
214 
215 }
View Code

三:导入Excel模板打印报表

1:生产厂家POI打印缺点:

1) 当静态文字变更时,需要修改代码

2) 样式代码繁多,不灵活,修改代码

3) 表格标题每页都出现

4) 打印加页脚,写入当前页总页数(报表引擎)

2:模板打印

1:用excel 2003书写模板文件

2:代码打印:只需要三步,一读取数据,二读取模板样式,三根据模板样式写入数据

       @RequestMapping("/cargo/outproduct/outProductPrint.action")

       public void print(String inputDate, HttpServletResponse response) throws FileNotFoundException, IOException, ParseException{

              /*

               * 操作步骤:

               * 1、获取数据

               * 2、POI写数据到文件:读模板样式,设置模板样式

               */

    //1:获取数据

              List<OutProduct> oList = contractService.findOutProduct(inputDate+"%");

             //2:读取模板文件

              Workbook wb = new HSSFWorkbook(new FileInputStream(new File("c:\tFACTORY.xls")));                         //打开模板文件

              Sheet sheet = wb.getSheetAt(0);                                   //打开第一个工作表

              Row nRow = null;

              Cell nCell = null;

              int rowNo = 2;                                                                     //行号

              int colNo = 1;                                                               //列号

             

              //处理标题

              nRow = sheet.getRow(0);                                                     //获得行对象

              nCell = nRow.getCell(1);                                               //获得单元格对象

              nCell.setCellValue(inputDate.replaceFirst("-0", "-").replaceFirst("-", "年")+"月份出货表");              //yyyy-MM 2010-08

             

              //获取模板文件中的样式

    //获取第2行第1列的客户名称样式

              nRow = sheet.getRow(2);

              nCell = nRow.getCell(1);

              CellStyle customNameStyle = nCell.getCellStyle();                 //获取客户名称样式

             //获取第2行第2列的合同编号样式

              nRow = sheet.getRow(2);

              nCell = nRow.getCell(2);

              CellStyle contractNoStyle = nCell.getCellStyle();

             //获取第2行第3列的产品编号样式

              nRow = sheet.getRow(2);

              nCell = nRow.getCell(3);

              CellStyle productNoStyle = nCell.getCellStyle();

             //获取第2行第4列的号码样式

              nRow = sheet.getRow(2);

              nCell = nRow.getCell(4);

              CellStyle cnumberStyle = nCell.getCellStyle();

             

              nRow = sheet.getRow(2);

              nCell = nRow.getCell(5);

              CellStyle factoryStyle = nCell.getCellStyle();

             

              nRow = sheet.getRow(2);

              nCell = nRow.getCell(6);

              CellStyle extStyle = nCell.getCellStyle();

             //获取第2行第7列的时间样式

              nRow = sheet.getRow(2);

              nCell = nRow.getCell(7);

              CellStyle dateStyle = nCell.getCellStyle();

             

              nRow = sheet.getRow(2);

              nCell = nRow.getCell(9);

              CellStyle tradeTermsStyle = nCell.getCellStyle();

             //3:往excel表中写数据

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

                     colNo = 1;

                     OutProduct op = oList.get(i);                                 //获取每个出货表对象

                    

                     nRow = sheet.createRow(rowNo++);                      //创建行

                     nRow.setHeightInPoints(24);                                         //行高

                    

                     nCell = nRow.createCell(colNo++);                        //创建单元格

                     nCell.setCellValue(op.getCustomName());

                     nCell.setCellStyle(customNameStyle);

                    

                     nCell = nRow.createCell(colNo++);

                     nCell.setCellValue(op.getContractNo());

                     nCell.setCellStyle(contractNoStyle);

                    

                     nCell = nRow.createCell(colNo++);

                     nCell.setCellValue(op.getProductNo());

                     nCell.setCellStyle(productNoStyle);

                    

                     nCell = nRow.createCell(colNo++);

                     nCell.setCellValue(op.getCnumber());

                     nCell.setCellStyle(cnumberStyle);

                    

                     nCell = nRow.createCell(colNo++);

                     nCell.setCellValue(op.getFactoryName());

                     nCell.setCellStyle(factoryStyle);

                    

                     nCell = nRow.createCell(colNo++);

                     nCell.setCellValue("附件");

                     List<String> extNameList = contractService.getExtName(op.getContractProductId());

                     String _extName = "";

                     if(extNameList!=null&&extNameList.size()>0){

                            for(String extName : extNameList){

                                   _extName += extName + " ";                        //换行符

                            }

                            _extName = _extName.substring(0,_extName.length()-1);            //去掉最后一个字符

                     }else{

                            _extName = "无";

                     }

                     nCell.setCellValue(_extName);

                     nCell.setCellStyle(extStyle);

                    

                     nCell = nRow.createCell(colNo++);

                     //nCell.setCellValue(UtilFuns.dateTimeFormat(op.getDeliveryPeriod()));       //利用工具类转类型,同时进行格式化

                     nCell.setCellValue(op.getDeliveryPeriod());

                     nCell.setCellStyle(dateStyle);

                    

                     nCell = nRow.createCell(colNo++);

                     //nCell.setCellValue(UtilFuns.dateTimeFormat(op.getShipTime()));

                     nCell.setCellValue(op.getShipTime());

                     nCell.setCellStyle(dateStyle);

                    

                     nCell = nRow.createCell(colNo++);

                     nCell.setCellValue(op.getTradeTerms());

                     nCell.setCellStyle(tradeTermsStyle);

              }

             

             

              DownloadUtil du = new DownloadUtil();

              ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();               //生成流对象

              wb.write(byteArrayOutputStream);

              du.download(byteArrayOutputStream, response, "出货表.xls");           //弹出下载框,用户就可以直接下载

       }

分析打印代码,读懂设计的重点;将原有的xls实现改造为xlsx实现。采用的poi模板打印,最后利用response进行的输出

 从总体看结构是,poiutil类中设置了细节性的设置信息,关于字体、图片、具体的线等。

在contractprint主体就是应用poiuti中 的格式设置和在本类中不同目标的设置样式按照预定样式填充货物数据信息,在填充完数据后进行打印。

3:插入图片

POI插入图片的原理,给定一个区域,图片自动伸缩到整个区域,为了图片不失真,要提前计算好单元格整个区域的高度和宽度。

HSSFPatriarch patriarch = sheet.createDrawingPatriarch();           //add picture

poiUtil.setPicture(wb, patriarch, rootPath+"make/xlsprint/logo.jpg", curRow, 2, curRow+4, 2);

4:合并单元格

合同单元格操作时,操作的是合并前的第一个单元格,它的样式,只能设置第一个

    //合并单元格,新对象,不会覆盖合并的那些单元格,只是遮住,从rowNo行到rowNo行,从第0列到第六列 进行合并

              sheet.addMergedRegion(new CellRangeAddress(rowNo, rowNo, 0, 6));                    

5:其他

1) 插入线

2) 处理一款货物,还是两款货物,打印时样式

3) 换行

4) 人民币前缀样式

HSSFDataFormat format = wb.createDataFormat();

return format.getFormat(""¥"#,###,###.00"); // 设置格式

#代表一位数值,这位数存在,就显示这位数字;这位数不存在,不显示;

0代表一位数值,这位数存在,就显示这位数字;这位数不存在,显示0;

5) 公式

       nCell.setCellType(HSSFCell.CELL_TYPE_FORMULA);

       nCell.setCellFormula("F"+String.valueOf(curRow)+"*H"+String.valueOf(curRow));

7) 分页

                     if(p>0){

                            sheet.setRowBreak(curRow++);  //在第startRow行设置分页符

                     }

9) 单元格自适应高度

float height = poiUtil.getCellAutoHeight(printMap.get("Request"), 12f);             //自动高度

原文地址:https://www.cnblogs.com/nullering/p/13341890.html