POI Excel讀取圖片對應位置和順序生成圖片方法

POI EXCEL 03 07 版本圖片讀取 和寫入 操作

        <!-- maven poi 引用包-->
       <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.17</version>
        </dependency>
package rainJob.com.exercise;

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.junit.jupiter.api.Test;

import java.io.*;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @auth xiaoyu
 * @desciption 利用poi  讀取 寫出圖片操作。
 * @Date 13:13 2018/5/25
 */
public class PoiExercise {

    @Test
    public void mergerData() throws IOException, InvalidFormatException {
        //讀取文件地址
        File file = new File("C:\\Users\\lenovo\\Desktop\\test.xls");
        //最終返回值
        LinkedList<LinkedHashMap<String, Object>> linkedHashMaps = new LinkedList<>();
        //爲了給03版本賦值
        InputStream inputStream = new FileInputStream(file);
        Workbook workbook = null;
        if (file.getName().matches(".xlsx")) {
            //獲取工作簿
            workbook = new XSSFWorkbook(file);
        } else {
            workbook = new HSSFWorkbook(inputStream);
        }
        //這裏可以寫成fori形式,因爲我是測試的demo 所以下標就爲0了
        Sheet sheetAt = workbook.getSheetAt(0);
        //一行可能有多組圖片。picture方法獲取指定行 列 和圖片二進制數組。
        Map<Integer, Map<Integer, byte[]>> picture = picture(sheetAt);
        //獲取文本行。我覺得就只是CellTypeEnum 枚舉裏的這些纔會讀到
        int physicalNumberOfRows = sheetAt.getLastRowNum();
        //記錄第一行爲表頭
        LinkedList<String> fieldName = new LinkedList<>();
        //獲取第一行信息
        Row row1 = sheetAt.getRow(0);
        int lastCellNum = row1.getPhysicalNumberOfCells();
        for (int i = 0; i < lastCellNum; i++) {
            fieldName.add(i, row1.getCell(i).getStringCellValue());
        }
        //從第二行開始,獲取信息
        for (int i = 1; i <= physicalNumberOfRows; i++) {
            Row row = sheetAt.getRow(i);
            //只能獲取CellTypeEnum 枚舉裏的這些纔會讀到
            int lastCell = row.getPhysicalNumberOfCells();
            //記錄一行的value值
            LinkedHashMap<String, Object> rowValue = new LinkedHashMap<>();
            for (int j = 0; j < lastCell; j++) {
                String name = fieldName.get(j);
                Cell cell = row.getCell(j);
                if (cell == null) continue;
                //進行拿到結果值
                Object cellValue = getObject(cell);
                rowValue.put(name, cellValue);
            }
            linkedHashMaps.add(rowValue);
        }
        //爲了防止文本行沒有數據 光有圖片的情況
        if (!picture.isEmpty()) {
            picture.forEach((k, v) -> {
                LinkedHashMap<String, Object> stringObjectLinkedHashMap = null;
                //如果我這個行有文本對應就爲true 沒有就是false
                boolean fal = false;
                if ((k - 1) >= linkedHashMaps.size()) {
                    stringObjectLinkedHashMap = new LinkedHashMap<>();
                } else {
                    fal = true;
                    stringObjectLinkedHashMap = linkedHashMaps.get(k - 1);
                }
                LinkedHashMap<String, Object> finalStringObjectLinkedHashMap = stringObjectLinkedHashMap;
                if (!v.isEmpty()) {
                    v.forEach((key, val) -> {
                        String name = fieldName.get(key);
                        int cellLength = finalStringObjectLinkedHashMap.keySet().toArray().length;
                        //對應圖片的位置進行賦值。
                        if (key >= cellLength) {
                            for (int i = cellLength; i < key; i++) {
                                finalStringObjectLinkedHashMap.put(fieldName.get(i), null);
                            }
                        }
                        finalStringObjectLinkedHashMap.put(name, val);
                    });
                    if (fal) {
                        linkedHashMaps.remove(k - 1);
                        if ((k - 1) > linkedHashMaps.size()) {
                            linkedHashMaps.add(finalStringObjectLinkedHashMap);
                        } else linkedHashMaps.add((k - 1), finalStringObjectLinkedHashMap);
                    } else {
                        //如果不存在文本行直接後面追加。沒生成空行。也可以你們想生成就生成。
                        linkedHashMaps.add(finalStringObjectLinkedHashMap);
                    }
                }
            });
        }
        //進行寫出。爲了節省造數據格式問題。
        writePicture(fieldName, linkedHashMaps);
    }

    /**
     * 判斷cell的枚舉 並對應處理成一個Object對象
     *
     * @param cell
     * @return
     */
    private Object getObject(Cell cell) {
        Object cellValue = null;
        switch (cell.getCellTypeEnum()) {
            case _NONE:
                cellValue = null;
                break;
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    if (cell.getNumericCellValue() < 1) {
                    } else {
                        //判斷字段類型是時間還是日期
                        SimpleDateFormat sdf = null;
                        String dateValue = DateUtil.getJavaDate(cell.getNumericCellValue()).toString();
                        //判斷時間類型還是日期類型。
                        boolean matches = dateValue.matches(".*00:00:00.*");
                        if (matches) {
                            sdf = new SimpleDateFormat("yyyy-MM-dd");
                        } else {
                            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        }
                        cellValue = sdf.format(DateUtil.getJavaDate(cell.getNumericCellValue()));
                    }
                } else {
                    //數字轉化
                    cellValue = String.valueOf(cell.getNumericCellValue());
                    cellValue = new BigDecimal(cellValue.toString());
                    BigDecimal bigDecimal = ((BigDecimal) cellValue).stripTrailingZeros();
                    cellValue = bigDecimal.toPlainString();
                }
                break;
            case STRING:
                cellValue = cell.getStringCellValue();
                break;
            case FORMULA:
                break;
            case BLANK:
                break;
            case BOOLEAN:
                break;
            case ERROR:
                break;
        }
        return cellValue;
    }

    /**
     * 讀取圖片幷包裝Map -->key  是rowIndex  -->value
     * 是map map-->key -->cellIndex  value->byte[]圖片二進制數組
     *
     * @param sheet
     * @return
     */
    private Map<Integer, Map<Integer, byte[]>> picture(Sheet sheet) {
        //map 返回值
        Map<Integer, Map<Integer, byte[]>> map = new LinkedHashMap();
        //sheet.getDrawingPatriarch() 返回工作表現有的圖形,如果還沒有,則返回null。
        if (sheet.getDrawingPatriarch() != null) {
            //甄別07
            if (sheet instanceof XSSFSheet) {
                XSSFSheet sheetTemp = (XSSFSheet) sheet;
                //此形狀組中的形狀列表
                for (XSSFShape shape : sheetTemp.getDrawingPatriarch().getShapes()) {
//                    若果形狀組是圖片 還有自定義圖形的情況。
                    if (shape instanceof XSSFPicture) {
                        XSSFPicture picture = (XSSFPicture) shape;
//                 獲取圖片的錨點
                        XSSFAnchor anchor = picture.getAnchor();
                        if (anchor instanceof XSSFClientAnchor) {
                            int row1 = ((XSSFClientAnchor) anchor).getRow1();
                            int cell1 = ((XSSFClientAnchor) anchor).getCol1();
                            setByte(map, row1, cell1, picture.getPictureData().getData());
                            map.put(row1, map.get(row1));
                        }
                    }
                }
            } else {
                //甄別03
                HSSFSheet sheetTemp = (HSSFSheet) sheet;
                //sheet.getDrawingPatriarch() 獲取drawingPatriarch的區域。
                Spliterator<HSSFShape> spliterator = sheetTemp.getDrawingPatriarch().spliterator();
                spliterator.forEachRemaining(shape -> {
                    if (shape instanceof HSSFPicture) {
                        HSSFPicture picture = (HSSFPicture) shape;
                        HSSFAnchor anchor = picture.getAnchor();
                        if (anchor instanceof HSSFClientAnchor) {
                            int row1 = ((HSSFClientAnchor) anchor).getRow1();
                            int cell1 = ((HSSFClientAnchor) anchor).getCol1();
                            setByte(map, row1, cell1, picture.getPictureData().getData());
                            map.put(row1, map.get(row1));
                        }
                    }
                });
            }
        }
        return map;
    }

    /**
     * 不管是03 還是07的通用方法,進行判斷是否存在那一行的那一列,進行添加數據
     *
     * @param map
     * @param row1
     * @param cell1
     * @param data
     */
    private void setByte(Map<Integer, Map<Integer, byte[]>> map, int row1, int cell1, byte[] data) {
        if (!map.containsKey(row1)) {
            Map<Integer, byte[]> map1 = new LinkedHashMap();
            map1.put(cell1, data);
            map.put(row1, map1);
        } else {
            Map<Integer, byte[]> integerMap = map.get(row1);
            if (!integerMap.containsKey(cell1)) {
                integerMap.put(cell1, data);
            }
        }
    }

    /**
     * poi 寫出帶有圖片的工具類
     * 只是07的03的就是改變下類就行。
     *
     * @param fieldNames
     * @param values
     * @throws InvalidFormatException
     * @throws IOException
     */
    public void writePicture(List<String> fieldNames, LinkedList<LinkedHashMap<String, Object>> values) throws InvalidFormatException, IOException {
        XSSFWorkbook workbook = new XSSFWorkbook();
        XSSFSheet sheet = workbook.createSheet();
        XSSFDrawing xssfdrawing = sheet.createDrawingPatriarch();
        XSSFRow rowOne = sheet.createRow(0);
        for (int i = 0; i < fieldNames.size(); i++) {
            XSSFCell cell = rowOne.createCell(i);
            cell.setCellValue(fieldNames.get(i));
        }
        for (int i = 0; i < values.size(); i++) {
            LinkedHashMap<String, Object> stringObjectLinkedHashMap = values.get(i);
            XSSFRow row = sheet.createRow((i + 1));
            Object[] keyArray = stringObjectLinkedHashMap.keySet().toArray();
            for (int j = 0; j < keyArray.length; j++) {
                Object cellValue = stringObjectLinkedHashMap.get(keyArray[j].toString());
                if (cellValue instanceof byte[]) {
                    //這塊設置的時候一定要col2比col1大要不圖片不會出來
                    //dx1 dy1 dx2 dy2 可以隨意指定吧。。沒弄清楚含義
//                    XSSFClientAnchor xssfClientAnchor = new XSSFClientAnchor(0, 0, 0, 0, j, i + 1, j + 1, i + 2);
                    //一開始無參構造不行 最後行了。。
                    XSSFClientAnchor xssfClientAnchor = new XSSFClientAnchor();
                    xssfClientAnchor.setCol1(j);
                    xssfClientAnchor.setCol2(j + 1);
                    xssfClientAnchor.setRow1(i + 1);
                    xssfClientAnchor.setRow2(i + 2);
                    //插入圖片
                    xssfdrawing.createPicture(xssfClientAnchor, workbook.addPicture((byte[]) cellValue, XSSFWorkbook.PICTURE_TYPE_PNG));
                } else {
                    XSSFCell cell = row.createCell(j);
                    if (cellValue != null) {
                        cell.setCellValue(cellValue.toString());
                    }
                }
            }
        }
        FileOutputStream fileOutputStream = new FileOutputStream("io.xlsx");
        workbook.write(fileOutputStream);
        workbook.close();
        fileOutputStream.close();
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章