功能需求是根据客户提供的excel模板,程序动态填充其中的一些数据。该模板包含大量的宏,刚拿到的时候头都要晕了,本人虽天天和电脑打交道,但是excel咱不是高手啊,什么宏,之前光听过,听着都觉得是高级的东西,就晕,但作为富有责任心的程序员,咱得攻克,也真的攻克了,现在鄙人去搞财务也没问题啊。
之前看各种评论说poi普遍对excel的支持更多一些,比较好用,具体jxl不好用在哪里,没有具体的说法,我就以为无伤大雅,而且项目之前的一些功能都是用jxl的,我就继续沿用jxl。首先来说下流程:
1.根据excel模板创建新工作簿,本质就是copy一份新的,在新的上面进行后续操作。
2.读取其中两个sheet页,对其中内容进行修改。
3.设置密码保护。
4.给第一个sheet页设置选中状态。
5.写出excel文件,关闭流之类的。
下面直接贴代码,这都是沥心之作啊,一笔一画都是心血,程序猿亏心亏脑啊,天气炎热,得好好休养。
首先是变量,这玩意是我自己项目需要,贴出来只为大家看代码看的明白,没啥意思的哈。
int colRefNo = 8; //RefNo所在列,列数是从0开始
int colVari = 9; //Variables所在列
int colChannel = 10; //Channel所在列
int colAFYP= 11; //AFYP所在列
int colNBSP= 12; //NBSP所在列
int colVONB= 14; //VONB所在列
int channelNum = 8; //excel模板channel的个数
int channelPart = 35; //每个channel的部分占多少行
int startRow = 18; //excel模板上数据的起始行,行数从0开始的
先贴jxl,断断续续搞了近一个月,中间端午回家,要不是因为它,我完全可以毫无牵挂地休上半个月到一个月的,说起都是泪啊。
public String modifyExcel(){
String infilepath = "c:/AA.xls";//模板文件位置
String filePath = "c:/test/";
String fileName = "jxlFile.xls";
String targetfile = filePath + fileName;//生成文件位置
File file = new File(targetfile);
//判断文件夹是否存在,不存在就创建
File parent = file.getParentFile();
if (parent != null && !parent.exists()) {
parent.mkdirs();
}
//创建新工作簿
Workbook rw = null;
WritableWorkbook wwb = null;
try {
rw = Workbook.getWorkbook(new File(infilepath)); //读入excel模板
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
try {
wwb = Workbook.createWorkbook(file, rw); //根据现有只读文件创建一个可写入的Excel工作薄对象
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
//读取第一张隐藏的工作表,取消隐藏属性
WritableSheet ws0 = wwb.getSheet(0);
ws0.setHidden(true);
System.out.println("===ws0.isHidden()="+ws0.isHidden()+"==ws0.isProtected()==="+ws0.isProtected());
WritableSheet wsPP = wwb.getSheet(2); //读取第三张工作表,PP
WritableSheet wsNP = wwb.getSheet(3); //读取第四张工作表,NP
wsPP = modifySheet(wsPP,"PP"); //对PP修改内容
wsNP = modifySheet(wsNP,"NP"); //对NP修改内容
SheetSettings ssPP = wsPP.getSettings();//设置PP的密码保护
ssPP.setPassword("ABCDEFG");
ssPP.setProtected(true);
SheetSettings ssNP = wsNP.getSettings();//设置NP的密码保护
ssNP.setPassword("ABCDEFG");
ssNP.setProtected(true);
ssNP.setSelected(false);
//读取第二张的工作表,设置选中状态
WritableSheet ws1 = wwb.getSheet(1);
ws1.getSettings().setSelected(true);
//写入Excel对象
try {
wwb.write();
} catch (Exception e) {
return e.getMessage();
}
//关闭可写入的Excel对象
try {
wwb.close();
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
//关闭只读的Excel对象
rw.close();
return "文件"+fileName+"已生成在"+filePath+"下!";
}
private WritableSheet modifySheet(WritableSheet ws,String pnp) {
int start = startRow;
DailySalesBean dsb = new DailySalesBean();
dsb.setPnp(pnp);
for (int j= 0 ; j< channelNum; j++){
int end = start+channelPart;
for(int i= start;i< end;i++){
Cell cellRefNo = ws.getCell(colRefNo, i);
Cell cellVari = ws.getCell(colVari, i);
Cell cellChannel = ws.getCell(colChannel, i);
//获取excel中某些列的值作为查询条件
dsb.setRefno(ObjectUtil.isEmpty(cellRefNo.getContents())?"":cellRefNo.getContents());
dsb.setVari(ObjectUtil.isEmpty(cellVari.getContents())?"":cellVari.getContents());
dsb.setChannel(ObjectUtil.isEmpty(cellChannel.getContents())?"":cellChannel.getContents());
//根据条件得出数据结果
DailySalesBean dsb2 = getDailyData(dsb);
WritableCell afypCell = ws.getWritableCell(colAFYP,i);
if(afypCell.getType() == CellType.NUMBER ){//单元格的数据格式,保证是number类型,涉及到自动计算
Number afyp = (Number)afypCell;
afyp.setValue(Double.parseDouble(dsb2.getAfyp()));//修改单元格的数值
}
WritableCell nbspCell = ws.getWritableCell(colNBSP,i);
if(nbspCell.getType() == CellType.NUMBER ){
Number nbsp = (Number)nbspCell;
nbsp.setValue(Double.parseDouble(dsb2.getNbsp()));
}
WritableCell vonbCell = ws.getWritableCell(colVONB,i);
if(vonbCell.getType() == CellType.NUMBER ){
Number vonb = (Number)vonbCell;
vonb.setValue(Double.parseDouble(dsb2.getVonb()));
}
//上面是获取单元格,直接修改值。下面注释掉的是另外一种方法,是new一个新的单元格,设置完值之后,add到sheet页里面去,个人觉得有种多余,应该浪费资源会多一
//点。但是在将数据单元格改为字符串单元格,涉及到数据类型更改的时候,后一种方法就派上用场了。
/* CellFormat cf1 = null;
CellFormat cf2 = null;
CellFormat cf3 = null;
if(j==0 && k==1 ){
Cell afypCell_old = ws.getCell(colAFYP,i);
Cell nbspCell_old = ws.getCell(colNBSP,i);
Cell vonbCell_old = ws.getCell(colVONB,i);
cf1 = afypCell_old.getCellFormat();
cf2 = nbspCell_old.getCellFormat();
cf3 = vonbCell_old.getCellFormat();//为保持原有单元格的样式,譬如边框,颜色,字体之类的,需要获取原有样式赋到新单元格上
}
Number afypCell = new Number(colAFYP, i, Double.parseDouble(dsb2.getAfyp()));
afypCell.setCellFormat(cf1);
try {
ws.addCell(afypCell);
} catch (Exception e) {
e.printStackTrace();
}
Number nbspCell = new Number(colNBSP, i, Double.parseDouble(dsb2.getNbsp()));
nbspCell.setCellFormat(cf2);
try {
ws.addCell(nbspCell);
} catch (Exception e) {
e.printStackTrace();
}
Number vonbCell = new Number(colVONB, i, Double.parseDouble(dsb2.getVonb()));
vonbCell.setCellFormat(cf3);
try {
ws.addCell(vonbCell);
} catch (Exception e) {
e.printStackTrace();
}
*/
}
start += channelPart;
}
return ws;
}
再贴个简洁的POI代码:
public String modifyExcel(){
String infilepath = "c:/AA.xls";
String filePath = "c:/Sales_Daily_java/";
String fileNane = "InputTemplate-Sales_Daily_Draft.xls";
String targetfile = filePath + fileNane;
File file = new File(targetfile);
//判断文件夹是否存在,不存在就创建
File parent = file.getParentFile();
if (parent != null && !parent.exists()) {
parent.mkdirs();
}
//创建新工作簿
HSSFWorkbook wb = null;//创建97-03版excel,如果是07-10版,则XSSFWorkbook wb = null;
NPOIFSFileSystem fs = null;
try {
fs = new NPOIFSFileSystem(new File(infilepath));
} catch (Exception e1) {
e1.printStackTrace();
return "读取excel模板文件失败!";
}
try {
wb = new HSSFWorkbook(fs.getRoot(),true);
} catch (Exception e1) {
e1.printStackTrace();
return "创建excel文件失败!";
}
//读取第三张工作表,PP_DailyInput
Sheet spp = wb.getSheetAt(2);
//读取第四张工作表,NP_DailyInput
Sheet snp = wb.getSheetAt(3);
spp = modifySheet(spp,"PP"); //对PP_DailyInput修改内容
snp = modifySheet(snp,"NP"); //对NP_DailyInput修改内容
spp.protectSheet("XDFZALDEXCAVPGS");//设置PP_DailyInput Sheet的密码保护
snp.protectSheet("XDFZALDEXCAVPGS");//设置NP_DailyInput Sheet的密码保护
snp.setSelected(false);
//读取第二张的工作表,设置选中状态
Sheet s1 = wb.getSheetAt(1);
s1.setSelected(true);
//输出流文件,关闭流
FileOutputStream fileOut = null;
try {
fileOut = new FileOutputStream(targetfile);
wb.write(fileOut);
fileOut.flush();
fileOut.close();
} catch (Exception e) {
e.printStackTrace();
return "excel文件生成失败!";
}
try {
fs.close(); //一定要比上面的后关闭,不然write的时候会抛异常,文件写出不了
} catch (IOException e1) {
e1.printStackTrace();
}
return "文件"+fileNane+"已生成在"+filePath+"下!";
}
/**
* 获取单元格的值
* @param cell
* @return
*/
private String getCellValue(Cell cell){
String result = null;
switch (cell.getCellType()) {
case Cell.CELL_TYPE_STRING:
result = cell.getRichStringCellValue().getString();
break;
case Cell.CELL_TYPE_NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
result = cell.getDateCellValue().toString();
} else {
Double cellValue = cell.getNumericCellValue();
DecimalFormat df = new DecimalFormat("#.#");
result = df.format(cellValue);
}
break;
case Cell.CELL_TYPE_BOOLEAN:
result = Boolean.toString(cell.getBooleanCellValue());
break;
case Cell.CELL_TYPE_FORMULA:
result = cell.getCellFormula();
break;
default:
result ="";
}
if(StringUtils.isEmpty(result)){
result = "";
}
return result;
}
private Sheet modifySheet(Sheet ws,String pnp) {
int start = startRow;
DailySalesBean dsb = new DailySalesBean();
dsb.setPnp(pnp);
for (int j= 0 ; j< channelNum; j++){
int end = start+channelPart;
for(int i= start;i< end;i++){
Row row = ws.getRow(i);
Cell cellRefNo = row.getCell(colRefNo);
Cell cellVari = row.getCell(colVari);
Cell cellChannel = row.getCell(colChannel);
dsb.setRefno(getCellValue(cellRefNo));
dsb.setVari(getCellValue(cellVari));
dsb.setChannel(getCellValue(cellChannel));
DailySalesBean dsb2 = getDailyData(dsb);
Cell afypCell = row.getCell(colAFYP);
afypCell.setCellValue(Double.parseDouble(dsb2.getAfyp()));
Cell nbspCell = row.getCell(colNBSP);
nbspCell.setCellValue(Double.parseDouble(dsb2.getNbsp()));
Cell vonbCell = row.getCell(colVONB);
vonbCell.setCellValue(Double.parseDouble(dsb2.getVonb()));
}
start += channelPart;
}
ws.setForceFormulaRecalculation(true);//excel中有写计算公式,数据修改之后强制重新调用里面的公式自动计算
return ws;
}
现在来总结下吧,之所以最后UAT发布关头改变方法,是因为jxl生成出来的excel在用office2010或07打开的时候总弹出来俩数据丢失和数据格式丢失的alert框,这玩意给客户感觉得是多不好啊,而且客户给的excel模板比较恶心,貌似因为宏的原因隐藏了个sheet页,一打开的时候下面的sheet页切换不灵光,而且原有的sheet设置的tab颜色也丢了。如果用office2003打开,那就是直接都打不开了,一打开就直接excel停止工作。琢磨了三四天,各种资料查下来都说是excel各种版本不兼容之类的问题,大家混乱的解决方案下来我也没解决问题。痛心之下抱着死马当活马医的心态,在发布UAT的前一天晚上查询poi的相关资料,对比了下jxl和poi的不同写法,第二天一早动笔修改程序,换血用poi重写代码,那边在如火如荼地发布,解决发布过程中的各种问题,我这边淡定地写着代码,终于赶在他们解决完问题之前写完了代码,中午写完,测试的时候,心情那个忐忑啊,要是还不行,我估计就得撞墙去了。颤抖着手,咽着快餐,启动服务器,测试,生成,生成的excel完美,和模板一模一样,激动的我呀,小心肝都快飞出来了。没有alert框,sheet切换正常,tab颜色也在,perfect!!!经此一事,忠实拥戴poi,看了下poi的api,齐全的,各种office操作的东西,poi都有相应的方法可供调用。
参考文献:http://poi.apache.org/spreadsheet/quick-guide.html#Iterator,著名的Busy Developers' Guide to HSSF and XSSF Features,新手必看,比看API块
jxl和poi处理excel之比较的更多相关文章
-
使用jxl,poi读取excel文件
作用:在java后台添加一个方法,读取导入的excel内容,根据需要返回相应的sql语句,以完成对临时表的插入操作. 使用jxl读取excel文件 package com.sixthf.bi.sapp ...
-
OAF_文件系列11_实现OAF读写Excel包JXL和POI的区别(概念)
20150803 Created By BaoXinjian
-
Java EXCEL导入的两种方式JXL和POI
Excel导入有两个方法:JXL 和POI 1.JXL解析Excel public class JxlReadExcel { /** * JXL解析Excel * @author Da ...
-
Java导出数据为EXCEL的两种方式JXL和POI
JXL和POI导出数据方式的比较 POI支持excel2003和2007,而jxl只支持excel2003. 下面为测试代码: public class TestCondition { /** * 生 ...
-
jxl读写excel, poi读写excel,word, 读取Excel数据到MySQL
这篇blog是介绍: 1. java中的poi技术读取Excel数据,然后保存到MySQL数据中. 2. jxl读写excel 你也可以在 : java的poi技术读取和导入Excel了解到写入Exc ...
-
java使用jxl,poi解析excel文件
public interface JavaExcel { /** * 使用jxl写excel文件 */ public void writeJxlExcel(); /** * 使用jxl读excel文件 ...
-
java 使用jxl poi 操作excel
java操作excel 创建.修改 xls 文件 JAVA操作Excel文件 Java生成和操作Excel文件 java导出Excel通用方法 Java 实现导出excel表 POI Java PO ...
-
POI操作Excel
POI和Excel简介 JAVA中操作Excel的有两种比较主流的工具包: JXL 和 POI .jxl 只能操作Excel 95, 97, 2000也即以.xls为后缀的excel.而poi可以操作 ...
-
poi导出excel
Java使用poi组件导出excel报表,能导出excel报表的还可以使用jxl组件,但jxl想对于poi功能有限,jxl应该不能载excel插入浮动层图片,poi能很好的实现输出excel各种功能, ...
随机推荐
-
websphere性能调优之dump命令
websphere性能调优之dump命令 基于WebSphere 构建的企业应用,时常会出现性能问题,在严重的情况下还会提示出内存溢出,这是一件很让人恼怒的事情.在WebSphere Applicat ...
-
CentOS7 bonding配置
操作系统:CentOS Linux release 7.1.1503 (Core) 网卡适配器: eno1.eno2 bonding类型:mode=1 (active-backup),主-备份策略 网 ...
-
【mysql】关于硬件方面的一些优化
一.CPU最大性能模式 cpu利用特点 5.1 最高可用4个核 5.5 最高可用24核 5.6 最高可用64核心 一次query对应一个逻辑CPU 你仔细检查的话,有些服务器上会有的一个有趣的现象:你 ...
-
前端 解决swiper js 手动滑动一下后不能自动播放
用户操作swiper之后,是否禁止autoplay.默认为true:停止.如果设置为false,用户操作swiper之后自动切换不会停止,每次都会重新启动autoplay.操作包括触碰,拖动,点击pa ...
-
关于火狐浏览器不支持img onerror的办法
项目中,要使用到缺省图,除了火狐浏览器,其它浏览器都支持img onerror事件.我使用到的解决的办法就是给图片的外层标签加背景,背景图用的就是缺省图. 上代码 <img src=" ...
-
OpenERP新手易犯错误之res.model
接触OpenERP的人都感慨资料之少,尤其是XML中,出点错是相当郁闷的.尤其是新手.什么都别说了,有图有真相. 视图中关联模型name="model" ,而动作中name=&qu ...
-
mongodb 教程一
mongodb是nosql(not only sql)的一种方式 .是对不同于传统的关系型数据库的数据库管理系统的统称. NoSQL - 代表着不仅仅是SQL- 没有声明性查询语言- 没有预定义的模式 ...
-
ORACLE 动态注册和静态注册的区别(转)
1, oracle 10g 用netca方式建立的都默认为动态注册方式2,如果想改为静态注册的方式则在listener.ora 中加入如下内容即可 SID_LIST_LISTENER = (SID_L ...
-
oracle实现主键自增
首先,创建一张表: CREATE TABLE example( ID Number(4) NOT NULL PRIMARY KEY, NAME VARCHAR(25)); 然后,自定义一个序列(seq ...
-
关于SpringMVC
SpringMVC 原理:1.用户发送请求给服务器.url:user.do2.服务器收到请求.发现DispatchServlet可以处理.于是调用DispatchServlet.3.DispatchS ...