在开发管理软件时,经常需要对Excel进行读写操作,JAVA常用的操作Excel方式有jcob和POI(下载地址:http://download.csdn.net/detail/shuizhaoshui/9523962),POI纯JAVA环境,不需要安装office引用,但对office的兼容性比jcob稍次点,但对我们平时的开发已经足够,因此,我更倾向于使用POI进行excel处理,在.NET开发中添加NPOI引用,起到同样的效果。今天发表的这篇文章是对POI读写Excel的两个封装通用方法,对基础的导出Excel和读取Excel相对还是方便的,好了,直接上代码。
1、读取Excel
@SuppressWarnings({ "static-access" })
private static String getCellValue(HSSFCell hssfCell) {
if (hssfCell.getCellType() == hssfCell.CELL_TYPE_BOOLEAN) {
return String.valueOf(hssfCell.getBooleanCellValue());
} else if (hssfCell.getCellType() == hssfCell.CELL_TYPE_NUMERIC) {
return String.valueOf(hssfCell.getNumericCellValue());
} else {
return String.valueOf(hssfCell.getStringCellValue());
}
}
因为cell中存在不同的数据类型,上面方法是读取每个cell中值,转为字符串类型以便通用处理(其实不用统一转为字符串类型也可以,但是那样读取操作,判断相对复杂很多,不仅要对cell类型进行判断,还要通过反射对实体类型进行判断转换, 对平常的读取感觉没必要,可以放到统一的集合中(集合所有字段全部为string类型)提取完之后再进行类型转换,将一个通用的实体结合转换为自己需要的实体对象,我感觉这样还稍微方便一点。),所以我会建立一个字段足够多的javabean对象,用来数据统一处理
/**
* 读取Excel
* @param 要读取的Excel路径信息
* @param c 读入的实体类型(ExportFields)
* @return 返回读取的list结果
* @throws IOException
* @throws Exception
* @throws IllegalAccessException
*/
public static <T> List<T> ReadExcel(String filepath, Class<T> c)
throws IOException, Exception, IllegalAccessException {
List<T> list = new ArrayList<T>();
Field[] fields = c.getDeclaredFields();
InputStream is = new FileInputStream(filepath); //网络传输可改动 request.getInputStream()
@SuppressWarnings("resource")
HSSFWorkbook hbook = new HSSFWorkbook(is); //读取的内容
HSSFSheet xssfSheet = hbook.getSheetAt(0);//要读取的sheet</span>
if (xssfSheet == null) {
return list;
}
//逐行逐列进行读取
for (int rowNum = 1, rowcount = xssfSheet.getLastRowNum(); rowNum <= rowcount; rowNum++) {
HSSFRow xssfRow = xssfSheet.getRow(rowNum);
if (xssfRow == null) {
continue;
}
T obj = c.newInstance();//新建对象实例
for (int celNum = 0, celCount = xssfRow.getLastCellNum(); celNum < celCount; celNum++) {
HSSFCell hssCel = xssfRow.getCell(celNum);
String result = "";
if (hssCel != null) {
result = getCellValue(hssCel);
}
fields[celNum].setAccessible(true);//反射访问私有字段必设
fields[celNum].set(obj, result);//字段赋值
}
list.add(obj);
}
return list;
}
在一 个项目中上面读取方法的形参class对象就可以统一用自己建立的ExportFields 对象来处理,提取结束后,你可以把他转换为自己需要的对象,不管是Person对象还是Students对象,如果你自己对象所有字段都为string类型,那么可以直接传入自己建立的对象, 因此,上面的调用方法可以统一为:
List<ExportFields> list=ReadExcel("文件路径名",ExportFields.class);
对取完之后就可以对list集合进行自己需要的处理。
如果是网络传输读取可以对方法稍加改动,不用存储到本地,直接进行网络读取操作,读取代码可以这样来写。
public static <T> List<T> ReadExcel(HttpServletRequest request,String filepath, Class<T> c)
throws IOException, Exception, IllegalAccessException {
List<T> list = new ArrayList<T>();
InputStream is = request.getInputStream();
2、导出Excel
导出Excel相对更方便一点,考虑字段类型不用那么复杂,代码如下:
/**
* 导出操作布
* @param list 要传入的导出集合
* @param excelname 导出后的文件名及sheet名
* @param titles 导出excel的每列的名称
* @return
*/
private static <T> HSSFWorkbook Hssbook(List<T> list, String excelname,
String... titles) {
HSSFWorkbook hbook = new HSSFWorkbook();
HSSFSheet sheet = hbook.createSheet(excelname);
HSSFRow row = sheet.createRow(0);//默认导出的sheet 0,如果想导出多个sheet可以自己加参数判断
HSSFCellStyle hstyle = hbook.createCellStyle();
hstyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); //标题水平居中对齐
int count = titles.length; //cell标题的长度
for (int i = 0; i < count; i++) {
HSSFCell cell = row.createCell(i);
cell.setCellValue(titles[i]); //设置cell值
cell.setCellStyle(hstyle);
sheet.autoSizeColumn(i); //默认列宽度,如果需要自己可以设置指定宽度
}
Field[] fields = list.get(0).getClass().getDeclaredFields(); //获取要导出的字段属性
int fcoount = fields.length > count ? count : fields.length; //判断导出字段的长度,限定不会超过标题的长度
for (int i = 0, countl = list.size(); i < countl; i++) {
row = sheet.createRow(i + 1);
for (int j = 0; j < fcoount; j++) {
Field field = fields[j];
field.setAccessible(true); //私有字段必设
String fileString = "";
try {
Object obj = field.get(list.get(i)); //字段取值
if (obj != null) {
fileString = obj.toString(); //全部以字符串类型导出
}
row.createCell(j).setCellValue(fileString); //cell赋值
} catch (Exception e) {
e.printStackTrace();
}
}
}
return hbook;
}
字段的cell取值顺序是跟自己建立的对象的位置
顺序是一致的。默认每列必须有标题,这个是防止字段过多未赋值就不用对后面未赋值的字段读取。注释够详细了,具体的我也就不解释了,读取方法在后面,如下:
/**
* Excel 导出
* @param response
* @param list 要导出的List集合
* @param excelname 导出Excel的文件名和sheet名
* @param titles 导出excel的列标题
* @return 导出状态
*/
public static <T> String ExportExcel(HttpServletResponse response,
List<T> list, String excelname, String... titles) {
if (excelname == null || excelname.isEmpty()) {
excelname = new Date().getTime() + "";//如果标题未设置或者为空,则取当前时间<span style="font-family:arial, 宋体, sans-serif, tahoma, 'Microsoft YaHei';">值</span>
}
HSSFWorkbook hbook = Hssbook(list, excelname, titles);
response.setContentType("application/vnd.ms-excel");
try {
excelname = new String(excelname.getBytes("UTF-8"), "ISO-8859-1");//编码类型
} catch (Exception e2) {
}
response.setHeader("Content-disposition", "attachment;filename="
+ excelname + ".xls");
OutputStream ouputStream = null;
try {
ouputStream = response.getOutputStream();
hbook.write(ouputStream);
ouputStream.flush();
ouputStream.close();
hbook.close();
} catch (Exception e) {
try {
ouputStream.close();
hbook.close();
} catch (Exception e1) {
}
return "false";
}
return "ok";
}
上面要注意的是这句
excelname = new String(excelname.getBytes("UTF-8"), "ISO-8859-1");
这个编码类型要注意,防止中文标题乱码,java web里面默认的为 ISO-8859-1类型,因此要进行
转码处理。
在springMVC里面调用方法可以这样:
@RequestMapping(value = "ExportExcel")
public void ExportExcel(HttpServletRequest request, HttpServletResponse response)
throws Exception {
List<Person> listPerson = new ArrayList<Person>();
Person p1=new Person();
listPerson.add(p1);
String[] titles={ "测试","邮箱","年龄","姓名","其他"};
ExcelUtil.ExportExcel(response, listPerson,"测试title",titles);
// List<ExportFields> listExportFields= new ArrayList<ExportFields>();
//ExcelUtil.ExportExcel(response, listPerson, "测试title","邮箱","年龄","姓名","其他");
}
上面形参传入的集合对象List<T>可以是 已经定义通用统一集合对象List<ExportFields> 或者其他你想传入的对象集合List<Person>。
页面请求方式如下:
<input type="button" οnclick="ExportExcel()" value="导出EXCEL" />
<script type="text/javascript">
function ExportExcel(){
location.href="ExportExcel";//请求地址
}
</script>
好了,结束 !基本的读取写入Excel方法,.NET开发中处理excel方法和这个差不多,下载相关程序集 ,利用反射,操作也挺方便的。
如果啥地方不对或者需要优化的地方还请大家批评指出,我会尽快改正,谢谢!