实现一个配置简单功能强大的excel工具类搞定excel导入导出(一)
对于J2EE项目导入导出Excel是最普通和实用功能,本工具类使用步骤简单,功能强大,只需要对实体类进行简单的注解就能实现导入导出功能,导入导出操作的都是实体对象.
请看一下这个类都有哪些功能:
* 1.实体属性配置了注解就能导出到excel中,每个属性都对应一列.
* 2.列名称可以通过注解配置.
* 3.导出到哪一列可以通过注解配置.
* 4.鼠标移动到该列时提示信息可以通过注解配置.
* 5.用注解设置只能下拉选择不能随意填写功能.
* 6.用注解设置是否只导出标题而不导出内容,这在导出内容作为模板以供用户填写时比较实用.
请看一下效果图:

请看一下使用步骤:
1.写一个实体类,并设置注解配置.
2.实例化一个ExcelUtil<T>对象,调用exportExcel或importExcel方法.
请看一个demo.
1.写一个实体类,并设置注解配置.
package com.tgb.lk.test03;import com.tgb.lk.util.ExcelVOAttribute;public class StudentVO {@ExcelVOAttribute(name = "序号", column = "A")private int id;@ExcelVOAttribute(name = "姓名", column = "B", isExport = true)private String name;@ExcelVOAttribute(name = "年龄", column = "C", prompt = "年龄保密哦!", isExport = false)private int age;@ExcelVOAttribute(name = "班级", column = "D", combo = { "五期提高班", "六期提高班","七期提高班" })private String clazz;@ExcelVOAttribute(name = "公司", column = "F")private String company;//get和set方法(略)...@Overridepublic String toString() {return "StudentVO [id=" + id + ", name=" + name + ", company="+ company + ", age=" + age + ", clazz=" + clazz + "]";}}2.实例化一个ExcelUtil<T>对象,调用exportExcel或importExcel方法.
(1)导出
package com.tgb.lk.test03;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.util.ArrayList;import java.util.List;import com.tgb.lk.util.ExcelUtil;/* * 使用步骤: * 1.新建一个类,例如StudentVO. * 2.设置哪些属性需要导出,哪些需要设置提示. * 3.设置实体数据 * 4.调用exportExcel方法. */public class ExportTest03 {public static void main(String[] args) {// 初始化数据List<StudentVO> list = new ArrayList<StudentVO>();StudentVO vo = new StudentVO();vo.setId(1);vo.setName("李坤");vo.setAge(26);vo.setClazz("五期提高班");vo.setCompany("天融信");list.add(vo);StudentVO vo2 = new StudentVO();vo2.setId(2);vo2.setName("曹贵生");vo2.setClazz("五期提高班");vo2.setCompany("中银");list.add(vo2);StudentVO vo3 = new StudentVO();vo3.setId(3);vo3.setName("柳波");vo3.setClazz("五期提高班");list.add(vo3);FileOutputStream out = null;try {out = new FileOutputStream("d:\\success3.xls");} catch (FileNotFoundException e) {e.printStackTrace();}ExcelUtil<StudentVO> util = new ExcelUtil<StudentVO>(StudentVO.class);// 创建工具类.util.exportExcel(list, "学生信息", 65536, out);// 导出System.out.println("----执行完毕----------");}}(2)导入
package com.tgb.lk.test03;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.util.List;import com.tgb.lk.util.ExcelUtil;public class ImportTest03 {public static void main(String[] args) {FileInputStream fis = null;try {fis = new FileInputStream("d:\\success3.xls");ExcelUtil<StudentVO> util = new ExcelUtil<StudentVO>(StudentVO.class);// 创建excel工具类List<StudentVO> list = util.importExcel("学生信息0", fis);// 导入System.out.println(list);} catch (FileNotFoundException e) {e.printStackTrace();}}}
看完使用步骤一定对封装的类迫不及待了吧,请继续往下看:
(1)注解实现类:
package com.tgb.lk.util;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)@Target( { java.lang.annotation.ElementType.FIELD })public @interface ExcelVOAttribute {/** * 导出到Excel中的名字. */public abstract String name();/** * 配置列的名称,对应A,B,C,D.... */public abstract String column();/** * 提示信息 */public abstract String prompt() default "";/** * 设置只能选择不能输入的列内容. */public abstract String[] combo() default {};/** * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写. */public abstract boolean isExport() default true;}(2)导入导出封装类:
package com.tgb.lk.util;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.lang.reflect.Field;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import jxl.Cell;import jxl.Sheet;import jxl.Workbook;import jxl.read.biff.BiffException;import org.apache.poi.hssf.usermodel.DVConstraint;import org.apache.poi.hssf.usermodel.HSSFCell;import org.apache.poi.hssf.usermodel.HSSFDataValidation;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.ss.util.CellRangeAddressList;/* * ExcelUtil工具类实现功能: * 导出时传入list<T>,即可实现导出为一个excel,其中每个对象T为Excel中的一条记录. * 导入时读取excel,得到的结果是一个list<T>.T是自己定义的对象. * 需要导出的实体对象只需简单配置注解就能实现灵活导出,通过注解您可以方便实现下面功能: * 1.实体属性配置了注解就能导出到excel中,每个属性都对应一列. * 2.列名称可以通过注解配置. * 3.导出到哪一列可以通过注解配置. * 4.鼠标移动到该列时提示信息可以通过注解配置. * 5.用注解设置只能下拉选择不能随意填写功能. * 6.用注解设置是否只导出标题而不导出内容,这在导出内容作为模板以供用户填写时比较实用. * 本工具类以后可能还会加功能,请关注我的博客: http://blog.csdn.net/lk_blog */public class ExcelUtil<T> {Class<T> clazz;public ExcelUtil(Class<T> clazz) {this.clazz = clazz;}public List<T> importExcel(String sheetName, InputStream input) {List<T> list = new ArrayList<T>();try {Workbook book = Workbook.getWorkbook(input);Sheet sheet = null;if (!sheetName.trim().equals("")) {sheet = book.getSheet(sheetName);// 如果指定sheet名,则取指定sheet中的内容.}if (sheet == null) {sheet = book.getSheet(0);// 如果传入的sheet名不存在则默认指向第1个sheet.}int rows = sheet.getRows();// 得到数据的行数if (rows > 0) {// 有数据时才处理Field[] allFields = clazz.getDeclaredFields();// 得到类的所有field.Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>();// 定义一个map用于存放列的序号和field.for (Field field : allFields) {// 将有注解的field存放到map中.if (field.isAnnotationPresent(ExcelVOAttribute.class)) {ExcelVOAttribute attr = field.getAnnotation(ExcelVOAttribute.class);int col = getExcelCol(attr.column());// 获得列号// System.out.println(col + "====" + field.getName());field.setAccessible(true);// 设置类的私有字段属性可访问.fieldsMap.put(col, field);}}for (int i = 1; i < rows; i++) {// 从第2行开始取数据,默认第一行是表头.Cell[] cells = sheet.getRow(i);// 得到一行中的所有单元格对象.T entity = null;for (int j = 0; j < cells.length; j++) {String c = cells[j].getContents();// 单元格中的内容.if (c.equals("")) {continue;}entity = (entity == null ? clazz.newInstance() : entity);// 如果不存在实例则新建.// System.out.println(cells[j].getContents());Field field = fieldsMap.get(j);// 从map中得到对应列的field.// 取得类型,并根据对象类型设置值.Class<?> fieldType = field.getType();if ((Integer.TYPE == fieldType)|| (Integer.class == fieldType)) {field.set(entity, Integer.parseInt(c));} else if (String.class == fieldType) {field.set(entity, String.valueOf(c));} else if ((Long.TYPE == fieldType)|| (Long.class == fieldType)) {field.set(entity, Long.valueOf(c));} else if ((Float.TYPE == fieldType)|| (Float.class == fieldType)) {field.set(entity, Float.valueOf(c));} else if ((Short.TYPE == fieldType)|| (Short.class == fieldType)) {field.set(entity, Short.valueOf(c));} else if ((Double.TYPE == fieldType)|| (Double.class == fieldType)) {field.set(entity, Double.valueOf(c));} else if (Character.TYPE == fieldType) {if ((c != null) && (c.length() > 0)) {field.set(entity, Character.valueOf(c.charAt(0)));}}}if (entity != null) {list.add(entity);}}}} catch (BiffException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();}return list;}/** * 对list数据源将其里面的数据导入到excel表单 * * @param sheetName * 工作表的名称 * @param sheetSize * 每个sheet中数据的行数,此数值必须小于65536 * @param output * java输出流 */public boolean exportExcel(List<T> list, String sheetName, int sheetSize,OutputStream output) {Field[] allFields = clazz.getDeclaredFields();// 得到所有定义字段List<Field> fields = new ArrayList<Field>();// 得到所有field并存放到一个list中.for (Field field : allFields) {if (field.isAnnotationPresent(ExcelVOAttribute.class)) {fields.add(field);}}HSSFWorkbook workbook = new HSSFWorkbook();// 产生工作薄对象// excel2003中每个sheet中最多有65536行,为避免产生错误所以加这个逻辑.if (sheetSize > 65536 || sheetSize < 1) {sheetSize = 65536;}double sheetNo = Math.ceil(list.size() / sheetSize);// 取出一共有多少个sheet.for (int index = 0; index <= sheetNo; index++) {HSSFSheet sheet = workbook.createSheet();// 产生工作表对象workbook.setSheetName(index, sheetName + index);// 设置工作表的名称.HSSFRow row;HSSFCell cell;// 产生单元格row = sheet.createRow(0);// 产生一行// 写入各个字段的列头名称for (int i = 0; i < fields.size(); i++) {Field field = fields.get(i);ExcelVOAttribute attr = field.getAnnotation(ExcelVOAttribute.class);int col = getExcelCol(attr.column());// 获得列号cell = row.createCell(col);// 创建列cell.setCellType(HSSFCell.CELL_TYPE_STRING);// 设置列中写入内容为String类型cell.setCellValue(attr.name());// 写入列名// 如果设置了提示信息则鼠标放上去提示.if (!attr.prompt().trim().equals("")) {setHSSFPrompt(sheet, "", attr.prompt(), 1, 100, col, col);// 这里默认设了2-101列提示.}// 如果设置了combo属性则本列只能选择不能输入if (attr.combo().length > 0) {setHSSFValidation(sheet, attr.combo(), 1, 100, col, col);// 这里默认设了2-101列只能选择不能输入.}}int startNo = index * sheetSize;int endNo = Math.min(startNo + sheetSize, list.size());// 写入各条记录,每条记录对应excel表中的一行for (int i = startNo; i < endNo; i++) {row = sheet.createRow(i + 1 - startNo);T vo = (T) list.get(i); // 得到导出对象.for (int j = 0; j < fields.size(); j++) {Field field = fields.get(j);// 获得field.field.setAccessible(true);// 设置实体类私有属性可访问ExcelVOAttribute attr = field.getAnnotation(ExcelVOAttribute.class);try {// 根据ExcelVOAttribute中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.if (attr.isExport()) {cell = row.createCell(getExcelCol(attr.column()));// 创建cellcell.setCellType(HSSFCell.CELL_TYPE_STRING);cell.setCellValue(field.get(vo) == null ? "": String.valueOf(field.get(vo)));// 如果数据存在就填入,不存在填入空格.}} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}}}try {output.flush();workbook.write(output);output.close();return true;} catch (IOException e) {e.printStackTrace();System.out.println("Output is closed ");return false;}}/** * 将EXCEL中A,B,C,D,E列映射成0,1,2,3 * * @param col */public static int getExcelCol(String col) {col = col.toUpperCase();// 从-1开始计算,字母重1开始运算。这种总数下来算数正好相同。int count = -1;char[] cs = col.toCharArray();for (int i = 0; i < cs.length; i++) {count += (cs[i] - 64) * Math.pow(26, cs.length - 1 - i);}return count;}/** * 设置单元格上提示 * * @param sheet * 要设置的sheet. * @param promptTitle * 标题 * @param promptContent * 内容 * @param firstRow * 开始行 * @param endRow * 结束行 * @param firstCol * 开始列 * @param endCol * 结束列 * @return 设置好的sheet. */public static HSSFSheet setHSSFPrompt(HSSFSheet sheet, String promptTitle,String promptContent, int firstRow, int endRow, int firstCol,int endCol) {// 构造constraint对象DVConstraint constraint = DVConstraint.createCustomFormulaConstraint("DD1");// 四个参数分别是:起始行、终止行、起始列、终止列CellRangeAddressList regions = new CellRangeAddressList(firstRow,endRow, firstCol, endCol);// 数据有效性对象HSSFDataValidation data_validation_view = new HSSFDataValidation(regions, constraint);data_validation_view.createPromptBox(promptTitle, promptContent);sheet.addValidationData(data_validation_view);return sheet;}/** * 设置某些列的值只能输入预制的数据,显示下拉框. * * @param sheet * 要设置的sheet. * @param textlist * 下拉框显示的内容 * @param firstRow * 开始行 * @param endRow * 结束行 * @param firstCol * 开始列 * @param endCol * 结束列 * @return 设置好的sheet. */public static HSSFSheet setHSSFValidation(HSSFSheet sheet,String[] textlist, int firstRow, int endRow, int firstCol,int endCol) {// 加载下拉列表内容DVConstraint constraint = DVConstraint.createExplicitListConstraint(textlist);// 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列CellRangeAddressList regions = new CellRangeAddressList(firstRow,endRow, firstCol, endCol);// 数据有效性对象HSSFDataValidation data_validation_list = new HSSFDataValidation(regions, constraint);sheet.addValidationData(data_validation_list);return sheet;}}
您是否有这样的需求呢:
1.实体类中存放的值是一个编码,而导出的文件中需要把编码转成有意义的文字.例如:实体类中性别用0,1表示,而希望导出的excel文件中是"男","女".
2.想对导入的内容加一些逻辑,例如:判断某些值不能为空.或判断年龄不能小于0且不能大于100.
这篇文章写的有点长了,上述需求实现请看下篇文章: http://blog.csdn.net/lk_blog/article/details/8007837
实现一个配置简单功能强大的excel工具类搞定excel导入导出
http://blog.csdn.net/lk_blog/article/details/8007777
http://blog.csdn.net/lk_blog/article/details/8007837
代码下载: http://download.csdn.net/detail/lk_blog/4588280
限于本人水平有限,很多地方写的并不完美,希望大家不吝赐教.如果觉得本文对您有帮助请顶支持一下,如果有不足之处欢迎留言交流,希望在和大家的交流中得到提高.