三、使用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("导出失败!");
}