巴拉巴拉
小魔仙

POI操作Java导入导出Excel,程序猿尽然对Excel做了不可描述!小伙伴们都惊呆了!

一个工具,关于Excel导入和导出的DEMO,基于POI为基础来编写的一套小工具。这两个部分导入只举了一个很简单的例子,主要是Excel的导出,为了作为记录和学习,使用了自定义注解和反射。

Java操作Excel主要分为两个poi和jxl,本文只介绍了POI。

POI官网:http://poi.apache.org/

本DEMO使用官网3.15版本。

第一部分:POI读取Excel,这里只做了一个简单的DEMO,主要的重头戏在下面的导出一块,所以这部分各位看官看看就好。

package com.againfly.poi;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;

import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;

public class ExcelRead {
    /*
     * 读取指定的一个excel文件,
     * 获取所有sheet名称
     * 指定第一个sheet,读取所有行内容
     */
    public static void main(String[] args) {
        Workbook wb = null;
        try {
            wb = ReadExcel("E://position.xls");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < wb.getNumberOfSheets(); i++) {
            System.out.println(i + ":" + wb.getSheetName(i));
        }
        Sheet sheet = wb.getSheetAt(0);
        
        int rowCount = sheet.getPhysicalNumberOfRows(); 
        System.out.println("rowCount:" + rowCount);

        for (int i = 0; i < rowCount; i++) {
            ReadRow(sheet.getRow(i));
        }
    }

    /**
     * 读取一个Excel文件,支持xls,xlsx
     * @param 文件路径名
     */
    public static Workbook ReadExcel(String path) throws FileNotFoundException {
        return ReadExcel(new File(path));
    }

    /**
     * 读取一个Excel文件,支持xls,xlsx
     * jdk1.7之后开始支持try后带括号,括号内可以写需要finally框内需要关闭流的对象
     * 前提是对象实现了Closeable接口
     * 使用这种写法之后IO流可以不再finally内手动关闭。
     * @param 文件对象
     */
    public static Workbook ReadExcel(File file) throws FileNotFoundException {
        if (null == file || !file.exists()) {
            throw new FileNotFoundException();
        }
        Workbook wb = null;
        try (FileInputStream in = new FileInputStream(file)) {
            wb = WorkbookFactory.create(in);
        } catch (IOException | EncryptedDocumentException | InvalidFormatException e) {
            e.printStackTrace();
        }
        return wb;
    }

    /**
     * 读取一行的内容
     * @param row
     */
    public static void ReadRow(Row row) {
        int cellCount = row.getPhysicalNumberOfCells(); // 获取总列数
        for (int i = 0; i < cellCount; i++) {
            Cell cell = row.getCell(i);
            System.out.print(CellValue(cell) + "\t");
        }
        System.out.println();
    }

    public static SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");

    /**
     * 使用POI4.0版本时会失效。 目前使用POI3.15。 
     * 将单元格中的内容并转为String格式。
     */
    @SuppressWarnings("deprecation")
    public static String CellValue(Cell cell) {
        String space = "";
        if (null == cell) {
            return space;
        }
        int cellType = cell.getCellType();
        String cellValue = null;
        switch (cellType) {
        case Cell.CELL_TYPE_STRING: // 文本
            cellValue = cell.getStringCellValue();
            break;
        case Cell.CELL_TYPE_NUMERIC: // 数字、日期
            if (DateUtil.isCellDateFormatted(cell)) {
                cellValue = fmt.format(cell.getDateCellValue()); // 日期型
            } else {
                cellValue = String.valueOf(cell.getNumericCellValue()); // 数字
            }
            break;
        case Cell.CELL_TYPE_BOOLEAN: // 布尔型
            cellValue = String.valueOf(cell.getBooleanCellValue());
            break;
        case Cell.CELL_TYPE_BLANK: // 空白
        case Cell.CELL_TYPE_ERROR: // 错误
        case Cell.CELL_TYPE_FORMULA: // 公式
        default:
            cellValue = space;
        }
        return cellValue;
    }
}

 

=====================华丽分割线========================

第二部分:POI导出Excel,这里做的稍微充分一点,但一样只是一个DEMO,使用了自定义注解和反射写的一个工具类。

先列出使用效果,再看实现逻辑:

实体类:Book.java,本代码中省略所有get和set方法。

package com.againfly.poi;

import java.sql.Timestamp;

public class Book {

    private int id;

    @ExcelField("姓名")
    private String name;

    @ExcelField(name = "时间", format = "yyyy年MM月dd日 HH:mm:ss")
    private Timestamp time;
    
    @ExcelField(serialize = false)
    private String UUID;

}

执行方法:其实就是简单的生成了两个Book对象,并且放到了一个List里面,之后又使用了即将出现的Demo

package com.againfly.poi;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class Main {
    public static void main(String[] args){
        Book book = new Book();
        book.setId(1);
        book.setName("巨人的陨落");
        book.setTime(new Timestamp(System.currentTimeMillis()));
        book.setUUID(UUID.randomUUID().toString());
        
        Book book2 = new Book();
        book2.setId(2);
        book2.setName("每周工作四小时");
        book2.setTime(new Timestamp(System.currentTimeMillis()));
        book2.setUUID(UUID.randomUUID().toString());

        List<Book> list = new ArrayList<>();
        list.add(book);
        list.add(book2);
        
        ExcelWrite<Book> excelWrite = new ExcelWrite<Book>();
        excelWrite.init(list);
        excelWrite.outWook("E:/book.xls");
    }
}

输出效果图:

poi_excel_screenshot

 

还是蛮复合我要的功能的,接下来开始贴出代码。

首先是自定义注解类:

package com.againfly.poi;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Target(ElementType.FIELD):该注解只能注解在字段上
 * @Retention(RetentionPolicy.RUNTIME):该注解可以保留到运行期,可以通过反射找到本注解值
 * @Documented:表明这个注解应该被 javadoc工具记录
 * @author Jecced
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExcelField {
    /**
     * 导出的Excel的字段名称
     * 当name不为空时,忽略value的值
     */
    public String name() default "";
    
    /**
     * 导出的Excel的字段名称
     * value的意思是字段的默认值
     * 可以直接使用默认注解,但是不指定名称例如:@ExcelField("字段名")
     * 需要注意的是,当name不为空时,value字段自动失效。
     */
    public String value() default "";
    
    /**
     * 是否对本字段进行序列化操作,默认值为true
     * 如果你对某个字段不需要进行序列化操作,可以设置本注解值为false
     * 这样就能忽略这个字段进行输出
     * 例如:@ExcelField(serialize = false)
     */
    public boolean serialize() default true;
    
    /**
     * 当一个字段为Date时,使用本字段可以序列化输出的时间格式
     * 在一个属于Date的字段使用该注解属性时,无效
     */
    public String format() default "";
}

代码实现逻辑:ExcelWrite.java

package com.againfly.poi;

import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

public class ExcelWrite<T> {

    private List<Field> serializeFieldList = null;

    private List<T> data;

    /**
     * 初始化将要序列化的list数据
     * 读取对象,通过反射查询需要的字段
     */
    public void init(List<T> list) {
        data = list;
        if (list.isEmpty()) {
            serializeFieldList = Collections.emptyList();
            return;
        }
        T obj = list.get(0);
        Field[] fields = obj.getClass().getDeclaredFields();
        serializeFieldList = new ArrayList<Field>(fields.length + 1);
        for (Field field : fields) {
            field.setAccessible(true);
            ExcelField excelField = field.getAnnotation(ExcelField.class);
            if (null == excelField || excelField.serialize()) {
                serializeFieldList.add(field);
            }
        }
    }

    private Workbook wb = null;
    private Sheet sheet = null;

    /**
     * 将文件输出到指定路径
     */
    public void outWook(String filePath) {
        File file = new File(filePath);
        outWook(file);
        file = null;
    }

    /**
     * 将文件输出到指定File文件
     */
    public void outWook(File file) {
        wb = new HSSFWorkbook();
        createHead();
        createRow();

        FileOutputStream out = null;
        try {
            out = new FileOutputStream(file);
            wb.write(out);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            safeClose(out);
            safeClose(wb);
        }
    }

    /**
     * 自带工具,关闭流
     * 让代码变的简洁
     */
    private static void safeClose(Closeable o) {
        if (null == o)
            return;
        try {
            o.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建Excel的样式和首行头
     * 通过读取字段名称和注解来生成
     */
    private void createHead() {
        sheet = wb.createSheet();
//      sheet.setDefaultColumnWidth((short) serializeFieldList.size() * 200);
        sheet.setDefaultColumnWidth(20);
        // 生成一个样式
        CellStyle style = wb.createCellStyle();
        // style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style.setAlignment(HorizontalAlignment.CENTER);
        Row row = sheet.createRow(0);

        for (int i = 0; i < serializeFieldList.size(); i++) {
            Cell cell = row.createCell((short) i);
            cell.setCellStyle(style);

            Field field = serializeFieldList.get(i);
            ExcelField excelField = field.getAnnotation(ExcelField.class);
            if (null == excelField || (excelField.name().trim().isEmpty() && excelField.value().trim().isEmpty())) {
                cell.setCellValue(field.getName());
            } else if (!excelField.name().trim().isEmpty()) {
                cell.setCellValue(excelField.name());
            } else {
                cell.setCellValue(excelField.value());
            }
        }
        style = null;
    }

    /**
     * 创建内容
     */
    private void createRow() {
        for (int i = 1; i <= data.size(); i++) {
            Row row = sheet.createRow((short) i);
            for (int c = 0; c < serializeFieldList.size(); c++) {
                try {
                    Field field = serializeFieldList.get(c);
                    row.createCell((short) c).setCellValue(value(field, data.get(i - 1)));
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 获取对象相应字段的值
     * 如果该字段是Date类型,并且有format注解,则返回格式化后的日期
     * 如果是Date类型,但是没有format注解,则使用默认的yyyy-MM-dd HH:mm:ss:SSS格式输出
     */
    private String value(Field field, T t) {
        field.setAccessible(true);
        Object obj = null;
        try {
            obj = field.get(t);
        } catch (IllegalArgumentException | IllegalAccessException e) {
            e.printStackTrace();
            return "";
        }
        if(null == obj){
            return "";
        }
        
        ExcelField excelField = field.getAnnotation(ExcelField.class);
        if(obj instanceof Date){
            String format = "yyyy-MM-dd HH:mm:ss:SSS";
            if(null != excelField && !excelField.format().trim().isEmpty()){
                format = excelField.format().trim();
            }
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            Date date = (Date) obj;
            String value = sdf.format(date);
            sdf = null;
            return value;
        }

        return obj.toString();
    }

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

赞(0) 打赏
如果文章对你有帮助,欢迎你来评价反馈。AgainFly » POI操作Java导入导出Excel,程序猿尽然对Excel做了不可描述!小伙伴们都惊呆了!
标签:

评论 3

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  • Q Q(选填)
  1. #3
    头像

    面对疾风吧,瓜娃子

    _123abc3年前 (2016-12-29)回复
  2. #2
    头像

    很骚很骚

    _123abc3年前 (2016-12-29)回复
  3. #1
    头像

    很骚很骚

    11113年前 (2016-11-29)回复

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏