Java POI生成Excel表文件

首先必须准备两个Jar包:

jakarta-poi-1.5.0-FINAL-20020506.jar.
commons-logging-1.0.jar

PoiTest.java

import org.apache.poi.hssf.usermodel.*;
import java.io.FileOutputStream; 

public class PoiTest {

public static void main(String[] args) throws Exception {

FileOutputStream fos = new FileOutputStream("d:\\foo.xls");
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet();
wb.setSheetName(0, "Matrix");
for(short i=0; i<50; i++) {
   HSSFRow row = s.createRow(i);
   for(short j=0; j<50; j++) {
   HSSFCell cell = row.createCell(j);
   cell.setCellValue(""+i+","+j);
   }
}
wb.write(fos);
fos.close();
}
}

ExcelCreate.java

import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.usermodel.*;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;

public class ExcelCreate {
public static void main(String[] args)throws IOException
{

   HSSFWorkbook wb = new HSSFWorkbook();//建立新HSSFWorkbook对象
   HSSFSheet sheet = wb.createSheet("new sheet");//建立新的sheet对象


   // Create a row and put some cells in it. Rows are 0 based.
   HSSFRow row = sheet.createRow((short)0);//建立新行

   // Create a cell and put a value in it.
   HSSFCell cell = row.createCell((short)0);//建立新cell
   cell.setCellValue(1);//设置cell的整数类型的值

   // Or do it on one line.
   row.createCell((short)1).setCellValue(1.2);//设置cell浮点类型的值
   row.createCell((short)2).setCellValue("test");//设置cell字符类型的值
   row.createCell((short)3).setCellValue(true);//设置cell布尔类型的值
   HSSFCellStyle cellStyle = wb.createCellStyle();//建立新的cell样式
   Workbook workBook = new Workbook();
   HSSFDataFormat hSSFDataFormat = new HSSFDataFormat(workBook);
   cellStyle.setDataFormat(hSSFDataFormat.getFormat("m/d/yy h:mm"));//设置cell样式为定制的日期格式
   HSSFCell dCell =row.createCell((short)4);
   dCell.setCellValue(new Date());//设置cell为日期类型的值
   dCell.setCellStyle(cellStyle); //设置该cell日期的显示格式
   HSSFCell csCell =row.createCell((short)5);
   csCell.setEncoding(HSSFCell.ENCODING_UTF_16);//设置cell编码解决中文高位字节截断
   csCell.setCellValue("中文测试_Chinese Words Test");//设置中西文结合字符串
   row.createCell((short)6).setCellType(HSSFCell.CELL_TYPE_ERROR);//建立错误cell

   // Write the output to a file
   FileOutputStream fileOut = new FileOutputStream("c:/workbook.xls");
   wb.write(fileOut);
   fileOut.close();
}
}

POI设置Excel的格式 字体样式 美化

Test2.java

import java.io.FileOutputStream;
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.hssf.util.HSSFColor;


public class Test2{

    public static void main(String[] args)throws Exception {
        //声明一个工作薄
         HSSFWorkbook wb=new HSSFWorkbook();
        //生成一个表格
         HSSFSheet sheet=wb.createSheet("表格1");
        //生成一个列
         HSSFRow row=sheet.createRow(0);
        //生成一个样式
         HSSFCellStyle style=wb.createCellStyle();
        //设置这些样式
         style.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
         style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
         style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
         style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
         style.setBorderRight(HSSFCellStyle.BORDER_THIN);
         style.setBorderTop(HSSFCellStyle.BORDER_THIN);
         style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        //生成一个字体
         HSSFFont font=wb.createFont();
         font.setColor(HSSFColor.VIOLET.index);
         font.setFontHeightInPoints((short)16);
         font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        //把字体应用到当前的样式
         style.setFont(font);
        //填充单元格
        for(short i=0;i<5;i++){
            //声明一个单元格
             HSSFCell cell=row.createCell(i);
            //设置单元格的字符值
             cell.setCellValue(new HSSFRichTextString("第"+i+"列"));
            //设置单元格的样式
             cell.setCellStyle(style);
         }
         FileOutputStream fout=new FileOutputStream("我的第一个EXCEL.xls");
        //输出到文件
         wb.write(fout);
         fout.close();
     }
}
public static void main(String[] args) {
        try {
             HSSFWorkbook wb = new HSSFWorkbook();
             HSSFSheet sheet = wb.createSheet();
             HSSFRow row = sheet.createRow(0);
             row.setHeight((short) 25);//目的是想把行高设置成25px
             FileOutputStream fileOut = new FileOutputStream("c:\\a.xls");
             wb.write(fileOut);
             fileOut.close();
         }
        catch (Exception e) {
             e.printStackTrace();
         }
     }

打开a.xls发现结果不是我想要的,第一行的高度都没有,没有报错说明代码有问题,为什么回没有高度呢?是不是单位不一样呢?

我把row.setHeight((short) 25);改成了row.setHeight((short) 250);结果发现第一行出来了,但是这是怎么一个换算关系呢?

我查看了一下导出的Excel第一行高是16像素,换算一下得出row.setHeight((short) 15.625);表示行高为一个像素,那么想设成几个像素就好做了。

比如row.setHeight((short) (15.625*n));//n为行高的像素数。
其实在API中还有一个HSSFRow 对象还有一个设置行高的函数setHeightInPoints(float height);这个函数中参数就是行高的像素数,比setHeight函数要方便多了。

行高设置完成了,接下来设置列宽

    public static void main(String[] args) {
        try {
             HSSFWorkbook wb = new HSSFWorkbook();
             HSSFSheet sheet = wb.createSheet();
             HSSFRow row = sheet.createRow(0);
             row.setHeight((short) 250);
             sheet.setColumnWidth((short) 0, (short) 250);
             FileOutputStream fileOut = new FileOutputStream("c:\\a.xls");
             wb.write(fileOut);
             fileOut.close();
         }
        catch (Exception e) {
             e.printStackTrace();
         }
     }

接下来说说sheet.setColumnWidth((short) 0, (short) 250);
第一个参数表示要为第几列设置,第二个参数表示列的宽度,看看上面的代码按说第一行第一列的单元格形状应该是个正方形,因为宽和高都是250,但是打开导出后的Excel发现宽度没有高度大,是个长方形,查看该列的宽度仅为7个像素,看来行高和列宽的单位是不一样的,同样换一算sheet.setColumnWidth((short) 0, (short) (35.7));表示高度为一个像素,同样设置列宽的像素为sheet.setColumnWidth((short) 0, (short) (35.7*n));//n为列高的像素数。

MergedCells.java

public class MergedCells {
     public static void main(String[] args) throws IOException {
         HSSFWorkbook wb = new HSSFWorkbook();
         HSSFSheet sheet = wb.createSheet("new sheet");

         HSSFRow row = sheet.createRow((short) 1);
         HSSFCell cell = row.createCell((short) 1);
         cell.setCellValue("This is a test of merging");

         sheet.addMergedRegion(new Region(1, (short) 1, 1, (short) 2));

         // Write the output to a file
         FileOutputStream fileOut = new FileOutputStream("workbook.xls");
         wb.write(fileOut);
         fileOut.close();

     }
}

WorkingWithFonts.java

public class WorkingWithFonts {
     public static void main(String[] args) throws IOException {
         HSSFWorkbook wb = new HSSFWorkbook();
         HSSFSheet sheet = wb.createSheet("new sheet");

         // Create a row and put some cells in it. Rows are 0 based.
         HSSFRow row = sheet.createRow((short) 1);

         // Create a new font and alter it.
         HSSFFont font = wb.createFont();
         font.setFontHeightInPoints((short) 24);
         font.setFontName("Courier New");
         font.setItalic(true);
         font.setStrikeout(true);

         // Fonts are set into a style so create a new one to use.
         HSSFCellStyle style = wb.createCellStyle();
         style.setFont(font);

         // Create a cell and put a value in it.
         HSSFCell cell = row.createCell((short) 1);
         cell.setCellValue("This is a test of fonts");
         cell.setCellStyle(style);

         // Write the output to a file
         FileOutputStream fileOut = new FileOutputStream("workbook.xls");
         wb.write(fileOut);
         fileOut.close();

     }
}
HSSFRow row = sheet2.createRow(2);
row.setHeightInPoints(240);
sheet2.setColumnWidth((short) 2, (short) 9000);

单元格的合并、数据行的分组以及Excel窗口的冻结
本来想把这三个东西分开来实现的,后来发现分开后内容都很少,于是就合在一起说吧。

那总不能干巴巴的列几个例子就完了吧,那就拿比较初级但又会经常遇到的表格类数据的统计的设计来做个小例子。

结果发现——还真够辛苦的。

这次先看效果图吧,其中的竖排并不是真正意义上Excel那种设置的竖排,而是稍微转变了一下输出的方式实现的,因为老外的英文单词没有这种竖排的可能(顶多是旋转,但是那样字体就变了)。

除此之外想到的另外一种竖排文字的实现方式就是样式旋转+字体旋转,没测试,不知道是否可用,谁有功夫实现一下,然后记得告诉我结果啊。

老样子,把核心的代码和简要的说明列出来大家看一下吧。

// 这里首先创建一个单元格样式对象,设置了四周的边框以及字体可以换行
// 其中的字体换行是用来竖向显示其中的一个单元格的
// 更好的一点儿做法是再做一个单独的单元格样式对象
// 要不然在处理自动列宽的时候可能会有点儿小问题
HSSFCellStyle normalStyle = wb.createCellStyle();
normalStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
normalStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
normalStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
normalStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
normalStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
normalStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
normalStyle.setWrapText(true);

// 合并单元格A1-C1,填入内容的时候添到第一个格子里就可以
// 但是注意一点:单元格合并後设置边框只在原第一个上有效,
// 如果想应用的合并後的整体,则需要一个个的Create出单元格并应用样式
// 这个明显是一个不太方便的操作,期待POI下一版的改进了
st.addMergedRegion(new Region(0, (short) 0, 0, (short) 2));
HSSFRow row = st.createRow(0);
HSSFCell cell = row.createCell((short) 0);
cell.setCellValue(new HSSFRichTextString("业务一览表"));
cell.setCellStyle(normalStyle);
row.createCell((short) 1).setCellStyle(normalStyle);
row.createCell((short) 2).setCellStyle(normalStyle);

// 设置列头,当然也可以一个一个格子的写,用循环感觉有些取巧而已
// 同样,需要单独给每个单元格应用样式对象
String[] seasonName = { "第一季度", "第二季度", "第三季度", "第四季度" };
for (short i = 3; i < 7; i++)
{
cell = row.createCell(i);
cell.setCellValue(new HSSFRichTextString(seasonName[i - 3]));
cell.setCellStyle(normalStyle);
}

// 这个是竖排文字的实现
// 目前POI没找到(或许没提供,或许我无知)让文字竖排的方法,
// HSSFCellStyle.setRotation()方法是设置旋转角度的,和竖排不太一样,
// 后来想了一下,因为只有中文等全角字符才有竖排的可能,
// 一个英文单词要是竖排看起来恐怕会非常怪异,不过不排除搞艺术的……
st.addMergedRegion(new Region(1, (short) 0, 6, (short) 0));
row = st.createRow(1);
cell = row.createCell((short) 0);
cell.setCellValue(new HSSFRichTextString("地\n区\n代\n理\nA"));
cell.setCellStyle(normalStyle);
for (int i = 2; i < 7; i++)
st.createRow(i).createCell((short) 0).setCellStyle(normalStyle);

// 属于地区的二级分类,竖向合并相邻的两个单元格,其他同上
String[] shopName = { "连锁店A", "连锁店B", "连锁店C" };
for (int i = 1; i < 6; i = i + 2)
{
row = st.createRow(i);
cell = row.createCell((short) 1);
cell.setCellValue(new HSSFRichTextString(shopName[(i - 1) / 2]));
cell.setCellStyle(normalStyle);
st.createRow(i + 1).createCell((short) 1).setCellStyle(normalStyle);
st.addMergedRegion(new Region(i, (short) 1, i + 1, (short) 1));
}

// 属于连锁店的下一级,基本也是创建出来然后赋值+应用样式
for (int i = 1; i < 7; i = i + 2)
{
cell = st.getRow(i).createCell((short) 2);
cell.setCellValue(new HSSFRichTextString("收入"));
cell.setCellStyle(normalStyle);
cell = st.getRow(i + 1).createCell((short) 2);
cell.setCellValue(new HSSFRichTextString("支出"));
cell.setCellStyle(normalStyle);
}

// 数据部分,直接Create然后应用样式,有数据的话这个地方就打数据好了
for (int i = 1; i < 7; i++)
for (short j = 3; j < 7; j++)
st.createRow(i).createCell(j).setCellStyle(normalStyle);

// 冻结Excel的窗口,边界为数据部分的边界
st.createFreezePane(3, 1);

// 按照连锁店级别分组(当然实际情况这样分组没啥意义)
for (int i = 1; i < 7; i = i + 2)
st.groupRow(i, i);

// 按照地区分组
st.groupRow(1, 5);

其实这样实现起来是不是很麻烦呢?答案是:是。

其实这只是举个例子,熟悉一下POI的各种API而已,真正要实现这样一个表格的时候,例如项目需要制作报表等等,通常的做法都是事先把格式一切的东西都手动制作好(这个做好了的文件在实际的项目里我们称之为“数据模板”,简称“模板”),然后在Java应用中适当的时机把这个文件读进来修改,最后再另存到指定的位置或者传递给下一个处理者(例如以流的方式送给Servlet等等),这样其实POI具体做的事情就是向模板里写业务的数据,还是很方便快捷的。

你可能感兴趣的:(java,poi,Excel)