三、使用java Excel操作Excel文件

Java Excel是一开放源码项目,通过它Java开发人员可以读取Excel文件的内容、创建新的Excel文件、更新已经存在的Excel文件。jxl 由于其小巧 易用的特点, 逐渐已经取代了 POI-excel的地位, 成为了越来越多的java开发人员生成excel文件的首选。Java  Excel的特征:

● 支持Excel 95-2000的所有版本 
         ● 生成Excel 2000标准格式 
         ● 支持字体、数字、日期格式化操作 
         ● 支持对单元格加阴影和加色彩;

● 修改存在的工作表;
         ● 支持图像和图表

● 日志记录可以定制

● 更小更快更省内存

应该说以上功能已经能够大致满足我们的需要。最关键的是这套API是纯Java的,并不依赖Windows系统,即使运行在Linux下,它同样能够正确的处理Excel文件。另外需要说明的是,这套API对图形和图表的支持很有限,而且仅仅识别PNG格式。在线帮助文档http://jexcelapi.sourceforge.net/resources/javadocs/2_6_10/docs/index.html

在这里我们将通过一些实例,学习掌握读取、新建、更新,其中也包括常见格式的设置:字体、颜色、背景、合并单元格等操作,有这些其实已经基本足够应付大部分问题了。

3.1环境配置

3.1.1下载

下载地址    http://www.andykhan.com/jexcelapi/

3.1.2 加入jar包

将jxl.jar拷贝到项目的Lib下

3.2 使用Java Excel Api 导出 Excel文件

下面我们在看如何使用Java Excel实现导出Excel表格?

代码如下:(实际开发中应封装到业务层组件中,然后在控制层中调用。这里直接写在控制层组件,如Servlet的doGet/doPost方法或Struts框架的execute方法中)

//获得输出流,该输出流的输出介质是客户端浏览器

 

  OutputStream output=response.getOutputStream();

 

  response.reset();

 

  response.setHeader("Content-disposition","attachment;           filename=temp.xls");

 

  response.setContentType("application/msexcel");

 

  //创建可写入的Excel工作薄,且内容将写入到输出流,并通过输出流输出给客户端浏览

 

  WritableWorkbook wk=Workbook.createWorkbook(output);

 

 

///创建可写入的Excel工作表

 

    WritableSheet sheet=wk.createSheet("成绩表", 0);

 

//把单元格(column, row)到单元格(column1, row1)进行合并。

 

//mergeCells(column, row, column1, row1);

 

  sheet.mergeCells(0,0, 4,0);//单元格合并方法

 

//创建WritableFont 字体对象,参数依次表示黑体、字号12、粗体、非斜体、不带下划线、亮蓝色

 

WritableFont titleFont=new WritableFont(WritableFont.createFont("黑体"),12,WritableFont.BOLD,false,UnderlineStyle.NO_UNDERLINE,Colour.LIGHT_BLUE);

 

//创建WritableCellFormat对象,将该对象应用于单元格从而设置单元格的样式

 

WritableCellFormat titleFormat=new WritableCellFormat();

 

//设置字体格式

 

titleFormat.setFont(titleFont);

 

//设置文本水平居中对齐

 

titleFormat.setAlignment(Alignment.CENTRE);

 

//设置文本垂直居中对齐

 

titleFormat.setVerticalAlignment(VerticalAlignment.CENTRE);

 

//设置背景颜色

 

titleFormat.setBackground(Colour.GRAY_25);

 

//设置自动换行

 

titleFormat.setWrap(true);

 

//添加Label对象,参数依次表示在第一列,第一行,内容,使用的格式

 

Label lab_00=new Label(0,0,"学员考试成绩一览表",titleFormat);

 

//将定义好的Label对象添加到工作表上,这样工作表的第一列第一行的内容为‘学员考试成绩一览表’并应用了titleFormat定义的样式

 

sheet.addCell(lab_00);

 

WritableCellFormat cloumnTitleFormat=new WritableCellFormat();

 

cloumnTitleFormat.setFont(new WritableFont(WritableFont.createFont("宋体"),10,WritableFont.BOLD,false));

 

cloumnTitleFormat.setAlignment(Alignment.CENTRE);

 

Label lab_01=new Label(0,1,"姓名",cloumnTitleFormat);

 

Label lab_11=new Label(1,1,"班级",cloumnTitleFormat);

 

Label lab_21=new Label(2,1,"笔试成绩",cloumnTitleFormat);

 

Label lab_31=new Label(3,1,"上机成绩",cloumnTitleFormat);

 

Label lab_41=new Label(4,1,"考试日期",cloumnTitleFormat);

 

  sheet.addCell(lab_01);

 

  sheet.addCell(lab_11);

 

  sheet.addCell(lab_21);

 

  sheet.addCell(lab_31);

 

  sheet.addCell(lab_41);

 

  sheet.addCell(new Label(0,2,"李明"));

 

  sheet.addCell(new Label(1,2,"As178"));

 

//定义数字格式

 

NumberFormat nf=new NumberFormat("0.00");

 

WritableCellFormat wcf=new WritableCellFormat(nf);

 

//类似于Label对象,区别Label表示文本数据,Number表示数值型数据

 

Number numlab_22=new Number(2,2,78,wcf);

 

sheet.addCell(numlab_22);

 

sheet.addCell(newNumber(3,2,87,new WritableCellFormat(new NumberFormat("#.##") )));

 

//定义日期格式

 

DateFormat df=new DateFormat("yyyy-MM-dd hh:mm:ss");

 

//创建WritableCellFormat对象

 

WritableCellFormat datewcf=new WritableCellFormat(df);

 

//类似于Label对象,区别Label表示文本数据,DateTime表示日期型数据

 

DateTime dtLab_42=new DateTime(4,2,new Date(),datewcf);

 

sheet.addCell(dtLab_42);  

 

//将定义的工作表输出到之前指定的介质中(这里是客户端浏览器)

 

wk.write();

 

//操作完成时,关闭对象,释放占用的内存空间  

 

wk.close();

  加下划线这部分代码是B/S模式中采用的输出方式,而不是输出到本地指定的磁盘目录。该代码表示将temp.xls的Excel文件通过应答实体(response)输出给请求的客户端浏览器,下载到客户端本地(保存或直接打开)。若要直接输出到磁盘文件可采用下列代码替换加下划线这部分代码

File file=new File("D://temp.xls");

WritableWorkbook wwb = Workbook.createWorkbook(file);

3.3高级操作

3.3.1数据格式化

在Excel中不涉及复杂的数据类型,能够比较好的处理字串、数字和日期已经能够满足一般的应用即可。

数据的格式化涉及到的是字体、粗细、字号等元素,这些功能主要由 WritableFont和WritableCellFormat类来负责。例如:

① WritableFont font=new WritableFont(WritableFont.createFont("宋体"),12,WritableFont.NO_BOLD );

② WritableCellFormat format1=new WritableCellFormat(font);

③ Label label=new Label(0,0,”data 4 test”,format1);

其中

I.指定了字串格式:字体为宋体,字号16,加粗显示。WritableFont有非常丰富的构造子,供不同情况下使用,jExcelAPI的java-doc中有详细列表,这里不再列出。

II. 处代码使用了WritableCellFormat类,这个类非常重要,通过它可以指定单元格的各种属性,如上例代码所示。

III. 处使用了Label类的构造子,指定了显示的位置,文本内容,字串被赋予的格式。

与Label类似的Number、DateTime,区别Label表示文本数据;Number表示数值数据,可使NumberFormat格式化数据;用DateTime表示日期型数据,可应用DateFormat格式化数据。

3.3.2单元格操作

Excel中很重要的一部分是对单元格的操作,比如行高、列宽、单元格合并等,所幸jExcelAPI提供了这些支持。这些操作相对比较简单,下面只介绍一下相关的API。

1、 合并单元格

WritableSheet.mergeCells(int m,int n,int p,int q);
 
//作用是从(m,n)到(p,q)的单元格全部合并,比如:
 
WritableSheet sheet=book.createSheet(“第一页”,0);
 
//合并第一列第一行到第六列第一行的所有单元格
 
sheet.mergeCells(0,0,5,0);
 
//合并既可以是横向的,也可以是纵向的。合并后的单元格不能再次进行合并,否则会触发异常。

2、 行高和列宽

writableSheet.setRowView(int i,int height);
 
//作用是指定第i+1行的高度,比如:
 
// 将第一行的高度设为200
 
sheet.setRowView(0,200);
 
WritableSheet.setColumnView(int i,int width);
 
//作用是指定第i+1列的宽度,比如:
 
//将第一列的宽度设为30
 
sheet.setColumnView(0,30);

3.4  从Excel文件读取数据表

我们就以导入3.2所产生的excel表为例,掌握如何编写导入Excel代码(该代码封装在业务层方法)

public List<ScoreInfo> loadScoreInfo(String xlsPath) throws IOException, BiffException{
 
//导入已存在的Excel文件,获得只读的工作薄对象
FileInputStream fis=new FileInputStream(xlsPath);
Workbook wk=Workbook.getWorkbook(fis);
//获取第一张Sheet表 
Sheet sheet=wk.getSheet(0);
//获取总行数
int rowNum=sheet.getRows();
//从数据行开始迭代每一行
for(int i=2;i<rowNum;i++){
ScoreInfo info=new ScoreInfo();        
//getCell(column,row),表示取得指定列指定行的单元格(Cell)
//getContents()获取单元格的内容,返回字符串数据。适用于字符型数据的单元格
//使用实体类封装单元格数据
info.setStuName(sheet.getCell(0, i).getContents());
info.setClassName(sheet.getCell(1, i).getContents());
//判断单元格的类型,单元格主要类型LABEL、NUMBER、DATE                    if(sheet.getCell(2,i).getType==CellType.NUMBER){
 
//转化为数值型单元格
NumberCell numCell=(NumberCell)sheet.getCell(2,i);
//NumberCell的getValue()方法取得单元格的数值型数据
info.setRscore(numCell.getValue());
 
}
if(sheet.getCell(3,i).getType==CellType.NUMBER){
NumberCell numCell=(NumberCell)sheet.getCell(3,i);
info.setRscore(numCell.getValue);
}
 
if(sheet.getCell(4,i).getType==CellType.DATE){
DateCell dateCell=(DateCell)sheet.getCell(4,i);
//DateCell的getDate()方法取得单元格的日期型数据
info.setDate(dateCell.getDate());
}
}
fis.close();
wk.close();
}

3.4  更新已存在的Excel文件

将3.2所产生的excel表(temp.xls)的第一条记录(excel文件的指第三行)的班级名称改为As179,代码如下:

File file=new File("d://temp.xls");
//导入已存在的Excel文件,获得只读的工作薄对象
Workbook wk=Workbook.getWorkbook(file);
//根据只读的工作薄对象(wk)创建可写入的Excel工作薄对象 
WritableWorkbook wwb=Workbook.createWorkbook(file, wk);
//读取第一张工作表 
WritableSheet sheet=wwb.getSheet(0);
///获得要编辑的单元格对象 
WritableCell cell=sheet.getWritableCell(1, 2);
//判断单元格的类型, 做出相应的转化 
if(cell.getType()==CellType.LABEL){
Label lable=(Label)cell;
//修改单元格的内容
lable.setString("As179");
}
wwb.write(); 
wwb.close(); 
wk.close();

对于更新已存在的Excel文件实际上就是获取已有工作薄对象(但是只读的),然后将获取的只读的工作薄对象转化为可写入的Excel工作薄对象(WritableWorkbook ),其他部分就是通过可写入WritableSheet 对象和可写入WritableCell 对象进行编辑。

例:

@RequestMapping(value = "/exp.htm")
public JSON exp(HttpServletRequest request, HttpServletResponse response) throws Exception {
    try {
        SessionUser sessionUser = this.getUser(request);
        String loginName = sessionUser.getLoginName();
        String kpiName = request.getParameter("kpiName");
        String department = request.getParameter("department");
        String name = request.getParameter("names");
        String taskStatus = request.getParameter("taskStatus");
        String flowStatus = request.getParameter("flowStatus");
        String yearNumber = request.getParameter("yearNumber");
        String monthStart = request.getParameter("monthStart");
        String monthEnd = request.getParameter("monthEnd");
        HashMap map = new HashMap();
        //判断是否是管理员
        map.put("isadmin", this.kpiSonService.isAdmin(sessionUser) + "");
        map.put("loginName", loginName);
        map.put("kpiName", kpiName);
        map.put("department", department);
        map.put("name", name);
        map.put("taskStatus", taskStatus);
        map.put("flowStatus", flowStatus);
        map.put("yearNumber", yearNumber);
        map.put("monthStart", monthStart);
        map.put("monthEnd", monthEnd);
        List<KpiView> list = kpiSonService.expEle(map);
        // 表头
        String[] outColName = {"序号","板块","部门","月份","编号","KPI名称","上年期末值","T1","T2","T3","上月实际值","上月工作说明","上月工作计划","本月实际值","本月工作说明","下月工作计划"};
        String[] outCol = {"numbers","plate","department","month","code","kpiName","finalValue","t1","t2","t3","lastValue","lastInstructions","lastPlan","actualValue","workInstructions","plan"};
        // 获得该类的所有属性的长度
        Field[] colName = new Field[outCol.length];
        for (Object obj : list) {
            for (int i =0; i < outCol.length; i++) {
                colName[i] = obj.getClass().getDeclaredField(outCol[i]);
            }
        }
        // 创建一个excel文档
        WritableWorkbook book = Workbook.createWorkbook(response.getOutputStream());
        // 设置响应方式
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        Calendar ca = Calendar.getInstance();
        String names = null;
        names = URLEncoder.encode(
                "战略KPI" + ca.get(Calendar.YEAR) + "-" + (ca.get(Calendar.MONTH) + 1) + "-"
                        + ca.get(Calendar.DATE) + ".xls", "UTF-8");
        response.addHeader("Content-Disposition",
                "attachment;filename=" + names + ";"
                        + "filename*=UTF-8''" + names);
        // 创建sheet工作表
        WritableSheet sheet = book.createSheet("战略KPI", 0);
        // 创建字体对象
        WritableFont font = new WritableFont(WritableFont.createFont("宋体"), 15);
        //标题
        WritableCellFormat titleFormat = new WritableCellFormat();
        titleFormat.setAlignment(Alignment.CENTRE);
        titleFormat.setFont(font);
        // 创建表头数据行格式化对象
        WritableCellFormat format = new WritableCellFormat();
        // 设置字体
        format.setFont(font);
        // 设置居中
        format.setAlignment(Alignment.CENTRE);
        //设置表头背景色
        format.setBackground(Colour.GRAY_25);
        // 设置自动换行
        format.setWrap(true);
        format.setBorder(jxl.format.Border.ALL, jxl.format.BorderLineStyle.THIN);
        for (int i = 0; i < outColName.length; i++) {
            Label lab = new Label(i, 0, outColName[i]);
            lab.setCellFormat(format);
            sheet.setColumnView(i, 30);
            // 添加表头
            sheet.addCell(lab);
        }
        // 添加表格体
        for (int i = 0; i < list.size(); i++) {
            for (int j = 0; j < colName.length; j++) {
                colName[j].setAccessible(true);
                String s = "";
                s = colName[j].get(list.get(i)) != null ? colName[j].get(list.get(i)) + "" : "";
                sheet.addCell(new Label(j, i + 1, s));
            }
        }
        book.write();
        book.close();
        return ResultData.successToJson("导出成功!");
    } catch (Exception e) {
        e.printStackTrace();
    }
    return ResultData.failureToJson("导出失败!");
}