poi導出excel有用的工具類整理

package com.sjdf.erp.common.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
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.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Font;
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.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import com.sjdf.erp.common.annotation.ExcelDesc;
import com.sjdf.erp.common.annotation.IsDictionary;
import com.sjdf.erp.common.constant.CommonPlatformConstant;
import com.sjdf.erp.common.constant.ConstBusiness;
import com.sjdf.erp.common.constant.purchase.Msg;
import com.sjdf.erp.common.dictionary.bean.sys.PlatformConstant;
import com.sjdf.erp.common.dictionary.cache.ConfigManager;
import com.sjdf.erp.common.net.HttpSocket;
import com.sjdf.erp.common.vo.Message;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

public class ExcelUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(ExcelUtils.class);

    public static final String XLSX = ".xlsx";
    public static final String XLS=".xls";
    public static final int IMG_HEIGTH = 30; // 圖片高度顯示像素
    public static final int IMG_WIDTH = 30; // 圖片寬度顯示像素

    /**
     * 解析Excel文件(.xls和.xlsx都支持)
     * @param file Excel的File對象
     * @return 解析後的JSONArray對象
     * @throws Exception
     */
    public static Message readExcel(File file) throws Exception {
        if (file == null || file.getName() == null) {
            throw new NullPointerException(Msg.UPLOAD_FILE_NULL);
        }
        String fileName = file.getName().toLowerCase();
        Workbook book = null;
        if (fileName.endsWith(XLSX)) {
            book = new XSSFWorkbook(file);
        } else if (fileName.endsWith(XLS)) {
            POIFSFileSystem poifsFileSystem = new POIFSFileSystem(new FileInputStream(file));
            book = new HSSFWorkbook(poifsFileSystem);
        }
        if (book != null) {
            Message message = read(book);
            book.close();
            return message;
        }
        return Message.createMessage(Msg.FILE_MUST_BE_XLS_OR_XLSX, Collections.emptyList());
    }

    /**
     * 解析Excel文件(.xls和.xlsx都支持)
     * @param file Excel的MultipartFile 對象
     * @return 解析後的JSONArray對象
     * @throws Exception
     */
    public static Message readExcel(MultipartFile file)throws Exception {
        if (file == null || file.getOriginalFilename() == null) {
            return Message.createMessage(Msg.UPLOAD_FILE_NULL, Collections.emptyList());
        }
        Workbook book = null;
        String name = file.getOriginalFilename().toLowerCase();
        if (name.endsWith(XLSX)) {
            book =new XSSFWorkbook(file.getInputStream());
        } else if (name.endsWith(XLS)) {
            book = new HSSFWorkbook(file.getInputStream());
        }
        if (book != null) {
            Message message = read(book);
            book.close();
            return message;
        }
        return Message.createMessage(Msg.FILE_MUST_BE_XLS_OR_XLSX, Collections.emptyList());
    }

    /**
     * 讀取不定列excel
     * @param file
     * @return List<List<String>>
     * @throws Exception
     */
    public static Message readIndeterminateExcel(MultipartFile file)throws Exception {
        if (file == null || file.getOriginalFilename() == null) {
            return Message.createMessage(Msg.UPLOAD_FILE_NULL, Collections.emptyList());
        }
        Workbook book = null;
        String name = file.getOriginalFilename().toLowerCase();
        if (name.endsWith(XLSX)) {
            book =new XSSFWorkbook(file.getInputStream());
        } else if (name.endsWith(XLS)) {
            book = new HSSFWorkbook(file.getInputStream());
        }
        if (book != null) {
            Message message = readIndeterminate(book);
            book.close();
            return message;
        }
        return Message.createMessage(Msg.FILE_MUST_BE_XLS_OR_XLSX, Collections.emptyList());
    }

    private static Message readIndeterminate(Workbook book) throws IOException {
        Sheet sheet = book.getSheetAt(0); 
        int rowEnd = sheet.getLastRowNum(); // 尾行下標
        Row firstRow = sheet.getRow(0);
        if (firstRow == null) {
            return Message.createMessage(Msg.EXCEL_ERROR, Collections.emptyList());
        }
        List<List<String>> data = new ArrayList<>();
        for(int i = 0; i <= rowEnd ; i++) {
            Row eachRow = sheet.getRow(i);
            if(eachRow == null) {
                continue;
            }
            int cellEnd = eachRow.getLastCellNum();
            List<String> rowData = new ArrayList<>();
            data.add(rowData);
            for (int k = 0; k < cellEnd; k++) {
                    String val = null;
                    try {
                        val = getValue(eachRow.getCell(k));
                    } catch (Exception e) {
                        LOGGER.error(i + "行" + k + "列獲取值錯誤", e);
                    }
                    rowData.add(val);
            }
        }
        Message message = Message.createMessage();
        message.setReturnData(data);
        return message;
    }

    /**
     * 獲取excel 表頭
     * @param file Excel的MultipartFile 對象
     * @return 返回解析json
     * @throws IOException 
     */
    public static Message getExcelHead(MultipartFile file) throws IOException {
        if (file == null || file.getOriginalFilename() == null) {
            return Message.createMessage(Msg.UPLOAD_FILE_NULL, Collections.emptyList());
        }
        Workbook book = null;
        String name = file.getOriginalFilename().toLowerCase();
        if (name.endsWith(XLSX)) {
            book =new XSSFWorkbook(file.getInputStream());
        } else if (name.endsWith(XLS)) {
            book = new HSSFWorkbook(file.getInputStream());
        }
        if (book != null) {
            Sheet sheetAt = book.getSheetAt(0);
            int firstRowNum = sheetAt.getFirstRowNum();
            Row row = sheetAt.getRow(firstRowNum);
            if (row == null) {
                return Message.createMessage(Msg.EXCEL_ERROR, Collections.emptyList());
            }
            int cellStart = row.getFirstCellNum();
            int cellEnd = row.getLastCellNum();
            JSONObject obj = new JSONObject();
            Integer num = 0;
            for (int j = cellStart; j < cellEnd; j++) {
                // 表頭遇到空格跳過
                String val = getValue(row.getCell(j));
                if (val == null || val.trim().length() == 0) {
                    continue;
                }
                obj.put(num, val);
                num += 1;
            }
            book.close();
            if (obj.isEmpty()) {
                return Message.createMessage(Msg.EXCEL_ERROR, Collections.emptyList());
            }
            Message message = Message.createMessage();
            message.setReturnData(obj);
            return message;
        }
        return Message.createMessage(Msg.FILE_MUST_BE_XLS_OR_XLSX, Collections.emptyList());
    }

    /**
     * 解析數據
     * @param sheet 表格sheet對象
     * @param book 用於流關閉
     * @return excel錶轉換後的JSONArray對象
     * @throws IOException
     */
    private static Message read(Workbook book) throws IOException {
        Sheet sheet = book.getSheetAt(0); 
        int rowStart = sheet.getFirstRowNum(); // 首行下標
        int rowEnd = sheet.getLastRowNum(); // 尾行下標
        // 獲取第一行JSON對象鍵
        Row firstRow = sheet.getRow(rowStart);
        if (firstRow == null) {
            return Message.createMessage(Msg.EXCEL_ERROR, Collections.emptyList());
        }
        int cellStart = firstRow.getFirstCellNum();
        int cellEnd = firstRow.getLastCellNum();
        Map<Integer, String> keyMap = new HashMap<Integer, String>();
        for (int j = cellStart; j < cellEnd; j++) {
            // 表頭遇到空格中止解析 
            String val = getValue(firstRow.getCell(j));
            if (val == null || val.trim().length() == 0) {
                cellEnd = j;
                break;
            }
            keyMap.put(j,val);
        }
        if (PlatformUtils.isEmpty(keyMap)) {
            return Message.createMessage(Msg.EXCEL_ERROR, Collections.emptyList());
        }
        // 獲取每行JSON對象的值
        JSONArray array = new JSONArray();
        // 若是首行與尾行相同,代表只有一行,返回表頭數據
        if (rowStart == rowEnd) {
            JSONObject object = new JSONObject();
            for (int i : keyMap.keySet()) {
                object.put(keyMap.get(i), "");
            }
            array.add(object);
            Message message = Message.createMessage();
            message.setReturnData(array);
            return message;
        }
        for(int i = rowStart+1; i <= rowEnd ; i++) {
            Row eachRow = sheet.getRow(i);
            JSONObject obj = new JSONObject();
            StringBuffer sb = new StringBuffer();
            for (int k = cellStart; k < cellEnd; k++) {
                if (eachRow != null) {
                    Cell cell = eachRow.getCell(k);
                    String val = getValue(cell);
                    sb.append(val); // 全部數據添加到裏面,用於判斷該行是否爲空
                    obj.put(keyMap.get(k),val);
                }
            }
            if (sb.toString().length() > 0) {
                array.add(obj);
            }
        }
        Message message = Message.createMessage();
        message.setReturnData(array);
        return message;
    }

    

    /**
     * 獲取每一個單元格的數據
     * @param cell 單元格對象
     * @param isKey 是否爲鍵:true-是,false-不是。 若是解析Json鍵,值爲空時報錯;若是不是Json鍵,值爲空不報錯
     * @return 該單元格數據
     * @throws IOException
     */
    private static String getValue(Cell cell) throws IOException {
        // 空白或空
        if (cell == null || cell.getCellType() == Cell.CELL_TYPE_BLANK ) {
            return "";
        }
        // 0. 數字 類型
        if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
            if (HSSFDateUtil.isCellDateFormatted(cell)) {
                Date date = cell.getDateCellValue();
                DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                return df.format(date);
            }
            cell.setCellType(Cell.CELL_TYPE_STRING);
            String val = cell.getStringCellValue()+"";
            return getEValue(val);
        }
        // 1. String類型
        if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
            String val = cell.getStringCellValue();
            if (val == null || val.trim().length() == 0) {
                return "";
            }
            return PlatformUtils.xssFilter(val.trim());
        }
        // 2. 公式 CELL_TYPE_FORMULA
        if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) {
            try {
                double cellValue = cell.getNumericCellValue();
                return String.valueOf(cellValue);
            } catch (Exception e) {
                return "0.00";
            }
        }
        // 4. 布爾值 CELL_TYPE_BOOLEAN
        if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
            return cell.getBooleanCellValue()+"";
        }
        // 5. 錯誤 CELL_TYPE_ERROR
        return "";
    }

    public static String getEValue(String s){
        // 非科學技術方法,直接去掉
        if (!s.contains("E")) {
            return s;
        }
        BigDecimal b = null;
        try {
            b = new BigDecimal(s);
        } catch (Exception e) {
            return s;
        }
        int len = Integer.valueOf(s.split("E")[1]);
        if (len < 0) {
            // 小數狀況(如:5.0000000000000001E-4)保留10位,去掉末尾的0
            return b.setScale(10, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toString();
        } else {
            // 其餘狀況:5.236E8
            String num = s.split("E")[0];
            if (len > 20) { // len 大於20位的話,數字過大,直接返回字符串
                return s;
            }
            num = num + "00000000000000000000";
            // 小數點向後移動 len 位,不夠添0
            return num.replace(".", "").substring(0, num.split("\\.")[0].length() + len);
        }
    }

    /**
     * 解析Excel,獲取List<Bean>
     * @param c Bean對象類型
     * @param file 上傳文件Excel
     * @return 數據合法的List<Bean>(前提是Bean屬性作了字段驗證)
     * @throws Exception 模版不正確異常
     */
    @SuppressWarnings("unchecked")
    public static <T> Message getBeanList(Class<T> c, MultipartFile file) {
        try {
            // 解析上傳文件爲JsonArray
            JSONArray arr = null;
            Message msg = readExcel(file);
            if (msg.hasErrorMessage()) {
                return msg;
            }
            arr = (JSONArray) msg.getReturnData();
            // 解析List<Bean>
            List<T> list = new ArrayList<T>();
            for (int i = 0; i < arr.size(); i++) {
                JSONObject obj = (JSONObject) arr.get(i);
                Message msg1 = getBean(c, obj);
                if (msg1.hasErrorMessage()) {
                    return msg1;
                } else {
                    list.add((T) msg1.getReturnData());
                }
            }
            Message msg2 = Message.createMessage();
            msg2.setReturnData(list);
            return msg2;
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            return Message.createMessage(e.getMessage(), Collections.emptyList());
        }
    }

    /**
     * 獲取單個Bean
     * @param c
     * @param obj
     * @return
     * @throws Exception
     */
    private static <T> Message getBean(Class<T> c, JSONObject obj) throws Exception{
        T t = c.newInstance();
        List<Field> fields = ASMUtils.getDeclaredFieldsRecursionSupper(c);
        for (int i = 0; i < fields.size(); i++) {
            Field field = fields.get(i);
            String fieldName = field.getName();
            // 獲取ExcleDesc註解屬性
            ExcelDesc excelDesc = field.getAnnotation(ExcelDesc.class);
            if (excelDesc != null) {
                String cname = excelDesc.cname();
                if (cname == null || cname.trim().length() == 0) { 
                    throw new NullPointerException(String.format("the field '%s' without cname value.", fieldName));
                }
                // 判斷是否必須爲必須字段,判斷cname
                String val = null;
                if (obj.has(cname)) {
                    val = obj.getString(cname);
                } else {
                    if (excelDesc.isRequired()) {
                        return Message.createMessage(Msg.EXCEL_ERROR);
                    } else {
                        continue;
                    }
                }
                // 判斷字段是否爲空,判斷iskey
                if (!PlatformUtils.hasText(val)) {
                    if (excelDesc.isKey()) {
                        return Message.createMessage(Msg.XXX_DATA_CAN_NOT_BE_NULL, cname);
                    }
                    // 非必須字段爲空狀況不繼續解析
                    continue;
                }
                // 獲取具體值
                field.setAccessible(true);
                // 獲取IsDictionary註解屬性
                IsDictionary dict = field.getAnnotation(IsDictionary.class);
                if (dict != null) {
                    int intVal = ConfigManager.getInstance().getAttrByName(dict.clazz(), dict.filed(), val);
                    field.set(t,intVal);
                    continue;
                }
                // 其他狀況根據類型賦值
                String fieldClassName = field.getType().getSimpleName();
                try {
                    if ("String".equalsIgnoreCase(fieldClassName)) {
                        field.set(t, val);
                    } else if ("boolean".equalsIgnoreCase(fieldClassName)) {
                        field.set(t, obj.getBoolean(cname));
                    } else if ("int".equalsIgnoreCase(fieldClassName) || "Integer".equals(fieldClassName)) {
                        field.set(t, obj.getInt(cname));
                    } else if ("double".equalsIgnoreCase(fieldClassName)) {
                        field.set(t, obj.getDouble(cname));
                    } else if ("long".equalsIgnoreCase(fieldClassName)) {
                        field.set(t, obj.getLong(cname));
                    } else if ("BigDecimal".equalsIgnoreCase(fieldClassName)) {
                        field.set(t, new BigDecimal(val));
                    }
                } catch (Exception e) {
                    LOGGER.error(e.getMessage(), e);
                    return Message.createMessage(Msg.XXX_DATA_ERROR, cname);
                }
            }
        }
        Message message = Message.createMessage();
        message.setReturnData(t);
        return message;
    }

    /**
     * Excel導出
     * @param title 導出Excel文件名稱
     * @param rowList 第一個List爲表頭,其他行爲表數據
     * @param resp HttpServletResponse 對象。不要用注入的resp,用controler方法中聲明的resp。不然會去尋找jsp
     * @throws IOException
     */
    public static void writeExcel(String title,List<List<Object>> rowList,HttpServletResponse resp) throws IOException{
        if (resp == null) {
            throw new NullPointerException("the HttpServletResponse is null");
        }
        SXSSFWorkbook book = warpSingleWorkbook(title, rowList);
        // 響應客戶端
        String filename = new String(title.getBytes("UTF-8"), "ISO-8859-1");
        resp.reset();
        resp.setHeader("Content-disposition", "attachment; filename=" + filename +XLS);
        resp.setContentType("application/vnd.ms-excel;charset=UTF-8");
        // 輸出Excel文件
        ServletOutputStream outputStream = resp.getOutputStream();
        book.write(outputStream);
        book.close();
        outputStream.close();
    }

    /**
     * Excel導出設置Workbook
     * @param title 導出Excel文件名稱
     * @param rowList 第一個List爲表頭,其他行爲表數據
     * @throws IOException
     */
    public static SXSSFWorkbook warpSingleWorkbook(String title,List<List<Object>> rowList) throws IOException {
        String filename = title;
        if (!PlatformUtils.hasText(title)) {
            filename = new SimpleDateFormat("yyMMddHHmmss").format(new Date());
        }
        if (rowList == null || rowList.isEmpty()) {
            throw new NullPointerException("the row list is null");
        }
        SXSSFWorkbook book = new SXSSFWorkbook();
        // 建立表
        setWorkBookData(book, filename, rowList);
        return book;
    }

    private static void setWorkBookData(SXSSFWorkbook book, String sheetName, List<List<Object>> rowList){
        Sheet sheet = book.createSheet(sheetName);
        Drawing patriarch = sheet.createDrawingPatriarch();
        // 設置表頭樣式
        CellStyle style = book.createCellStyle();
        // 設置居左
        style.setAlignment(HSSFCellStyle.ALIGN_LEFT);
        // 檢測表頭數據(表頭不容許數據爲空)
        List<Object> head = rowList.get(0);
        for (Object key : head) {
            if (!PlatformUtils.hasText(key.toString())) {
                throw new NullPointerException("there is a blank exist head row");
            }
        }
        // 寫數據
        int size = rowList.get(0).size();
        for (int i = 0; i < rowList.size(); i++) {
            List<Object> row = rowList.get(i);
            if (row == null || row.isEmpty()) {
                throw new NullPointerException("the "+(i+1)+"th row is null");
            }
            if (size != row.size()) {
                throw new IllegalArgumentException("the cell number of "+(i+1)+"th row is different form the first");
            }
            Row sr = sheet.createRow(i);
            for (int j = 0; j < row.size(); j++) {
                if (row.get(j) != null && row.get(j) instanceof URL) {
                    URL url = (URL)row.get(j);
                    sr.setHeight((short)(IMG_HEIGTH * IMG_WIDTH));
                    drawPictureIntoExcel(book, patriarch, i, j, url);
                } else {
                    setExcelValue(sr.createCell(j), row.get(j), style);
                }
            }
        }
    }

    /**
     * 導出多頁Excel
     * @param sheetMap key爲每一個頁的名稱,value爲表頭行+數據行
     * @return
     * @throws IOException
     */
    public static SXSSFWorkbook warpSingleWorkbook(Map<String, List<List<Object>>> sheetMap) throws IOException {
        SXSSFWorkbook book = new SXSSFWorkbook();
        for (String key : sheetMap.keySet()) {
            String sheetName = Pattern.compile("[[/*#]]").matcher(key).replaceAll("");
            setWorkBookData(book, sheetName, sheetMap.get(key));
        }
        return book;
    }


    /**
     * Excel導出設置Workbook(表頭自動換行)
     * @param title 導出Excel文件名稱
     * @param rowList 第一個List爲表頭,其他行爲表數據
     * @throws IOException
     */
    public static SXSSFWorkbook getSingleWorkbook(String title,List<List<Object>> rowList) throws IOException {
        String filename = title;
        if (!PlatformUtils.hasText(title)) {
            filename = new SimpleDateFormat("yyMMddHHmmss").format(new Date());
        }
        if (rowList == null || rowList.isEmpty()) {
            throw new NullPointerException("the row list is null");
        }
        SXSSFWorkbook book = new SXSSFWorkbook();
        // 建立表
        Sheet sheet = book.createSheet(filename);
        Font headFont = book.createFont();
        Drawing patriarch = sheet.createDrawingPatriarch();
        // 設置表頭樣式
        XSSFCellStyle style = (XSSFCellStyle)book.createCellStyle();
        CellStyle headStyle = book.createCellStyle();
        // 設置居左
        style.setAlignment(HSSFCellStyle.ALIGN_LEFT);
        headStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        headStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);// 水平居中
        headStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//設置垂直居中
        headStyle.setWrapText(true);// 自動換行
        headFont.setBoldweight(Font.BOLDWEIGHT_BOLD);// 加粗
        headStyle.setFont(headFont);
        // 檢測表頭數據(表頭不容許數據爲空)
        List<Object> head = rowList.get(0);
        Row headRow = sheet.createRow(0);
        for (int i = 0; i < head.size(); i++) {
            if (!PlatformUtils.hasText(head.get(i).toString())) {
                book.close();
                throw new NullPointerException("there is a blank exist head row");
            }
            setExcelValue(headRow.createCell(i), head.get(i), headStyle);
        }
        // 寫數據
        style.setWrapText(true);
        createBodyData(rowList, book, sheet, style, patriarch, false);
        return book;
    }

    /**
     * Excel寫網絡圖片
     * @param wb
     * @param patriarch
     * @param rowIndex
     * @param url
     */
    private static void drawPictureIntoExcel(SXSSFWorkbook wb,Drawing patriarch,int rowIndex, int cloumIndex, URL url){
        // rowIndex表明當前行
        try(InputStream is = url.openStream(); ByteArrayOutputStream swapStream = new ByteArrayOutputStream();) {
            byte[] buff = new byte[100];
            int rc = 0;
            while ((rc = is.read(buff, 0, 100)) > 0) {
                swapStream.write(buff, 0, rc);
            }
            // 設置圖片位置
            XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, cloumIndex, rowIndex, cloumIndex+1, rowIndex+1);
            anchor.setAnchorType(0);
            patriarch.createPicture(anchor, wb.addPicture(swapStream.toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG));
            swapStream.close();
        } catch (Exception e) {
            LOGGER.error("圖片請求失敗:" + url.toString());
        }
    }

    /**
     * Excel導出
     * @param title 導出Excel文件名稱
     * @param sheets 包含多個模塊的sheets也就是多個rowList,rowList 第一個List爲表頭,其他行爲表數據 
     * object 是一個list<Object>
     * @param resp HttpServletResponse 對象
     * @throws IOException
     */
    public static void writeExcels(String title, List<List<Object>> sheets, HttpServletResponse resp) throws IOException {
        if (resp == null) {
            throw new NullPointerException("the HttpServletResponse is null");
        }
        String filename = title;
        if (!PlatformUtils.hasText(filename)) {
            filename = new SimpleDateFormat("yyMMddHHmmss").format(new Date());
        }
        if (sheets == null || sheets.isEmpty()) {
            throw new NullPointerException("the row list is null");
        }
        // 建立表
        HSSFWorkbook book = wrapMultWorkbook(filename, sheets);
        // 響應客戶端
        filename = new String(filename.getBytes("UTF-8"), "ISO-8859-1");
        resp.reset();
        resp.setHeader("Content-disposition", "attachment; filename=" + filename +XLS);
        resp.setContentType("application/vnd.ms-excel;charset=UTF-8");
        // 輸出Excel文件
        book.write(resp.getOutputStream());
        book.close();
    }

    /**
     * Excel導出到項目目錄下
     * @param title 導出Excel文件名稱
     * @param sheets 包含多個模塊的sheets也就是多個rowList,rowList 第一個List爲表頭,其他行爲表數據 
     * object 是一個list<Object>
     * @param filePath 
     * @param resp HttpServletResponse 對象
     * @throws IOException
     */
    public static String writeExcelInWeb(String title, List<List<Object>> sheets, String filePath) throws IOException {
        String filename = title;
        if (!PlatformUtils.hasText(filename)) {
            filename = new SimpleDateFormat("yyMMddHHmmss").format(new Date());
        }
        if (sheets == null || sheets.isEmpty()) {
            throw new NullPointerException("the row list is null");
        }
        // 建立表
        String fileName = filename +".xls";
        HSSFWorkbook book = wrapMultWorkbook(filename, sheets);
        FileOutputStream stream = new FileOutputStream(filePath +"/" + fileName);
        book.write(stream);
        book.close();
        return fileName;
    }

    /**
     * 將數據寫入多個Excel sheet中
     * @param title 標題
     * @param sheets sheet
     * @param book Excel對象
     * @throws IOException
     */
    public static HSSFWorkbook wrapMultWorkbook(String title, List<List<Object>> sheets) throws IOException {
        HSSFWorkbook book = new HSSFWorkbook();
        for (int p = 0; p < sheets.size(); p++) {
            HSSFSheet sheet = book.createSheet(title+"_"+p);
            sheet.setDefaultRowHeightInPoints(CommonPlatformConstant.INT_15);
            // 檢測表頭數據(表頭不容許數據爲空)
            @SuppressWarnings("unchecked")
            List<String> head = (List<String>) sheets.get(p).get(0);
            for (Object key : head) {
                if (!PlatformUtils.hasText(key.toString())) {
                    book.close();
                    throw new NullPointerException("there is a blank exist head row");
                }
            }
            // 寫數據
            @SuppressWarnings("unchecked")
            List<Object> data = (List<Object>) sheets.get(p).get(0);
            int size = data.size();
            for (int i = 0; i < sheets.get(p).size(); i++) {
                @SuppressWarnings("unchecked")
                List<Object> row = (List<Object>) sheets.get(p).get(i);
                if (row == null || row.isEmpty()) {
                    book.close();
                    throw new NullPointerException("the "+(i+1)+"th row is null");
                }
                if (size != row.size()) {
                    book.close();
                    throw new IllegalArgumentException("the cell number of "+(i+1)+"th row is different form the first");
                }
                HSSFRow sr = sheet.createRow(i);
                for (int j = 0; j < row.size(); j++) {
                    if (row.get(j) == null) {
                        sr.createCell(j).setCellValue("");
                    } else {
                        Object value = row.get(j);
                        if (value instanceof Integer) {
                            HSSFCell cell = sr.createCell(j);
                            cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                            cell.setCellValue(Double.valueOf(value.toString()));
                        } else if (value instanceof BigDecimal) {
                            HSSFCell cell = sr.createCell(j);
                            cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                            cell.setCellValue(((BigDecimal)value).setScale(CommonPlatformConstant.INT_3, RoundingMode.HALF_UP).doubleValue());
                        } else {
                            sr.createCell(j).setCellValue(value.toString());
                        }
                    }
                }
            }
            for (int i = 0; i < head.size(); i++) {
                sheet.autoSizeColumn(i);
            }
        }
        return book;
    }

    /**
     * 設置Excel浮點數可作金額等數據統計
     * @param cell 單元格類
     * @param value 傳入的值
     */
    public static void setExcelValue(Cell cell,  Object value, CellStyle style){
        cell.setCellStyle(style);
        // 寫數據
        if (value == null) {
            cell.setCellValue("");
        }else {
            if (value instanceof Integer || value instanceof Long) {
                cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                cell.setCellValue(Long.valueOf(value.toString()));
            } else if (value instanceof BigDecimal) {
                cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                cell.setCellValue(((BigDecimal)value).setScale(CommonPlatformConstant.INT_3, RoundingMode.HALF_UP).doubleValue());
            } else {
                cell.setCellValue(value.toString());
            }
        }
    }

    /**
     * 設置Excel表體數據
     * @param rowList 表數據 : index 爲0 爲表頭
     * @param hasHead  是否包含表頭
     */
    public static void createBodyData(List<List<Object>> rowList, SXSSFWorkbook book, Sheet sheet, XSSFCellStyle style, Drawing patriarch, Boolean hasHead) throws IOException{
        int size = rowList.get(0).size();
        int startNum = 1;
        if(hasHead) {
            startNum = 0;
        }
        for (int i = startNum; i < rowList.size(); i++) {
            List<Object> row = rowList.get(i);
            if (row == null || row.isEmpty()) {
                book.close();
                throw new NullPointerException("the "+(i+1)+"th row is null");
            }
            if (size != row.size()) {
                book.close();
                throw new IllegalArgumentException("the cell number of "+(i+1)+"th row is different form the first");
            }
            Row sr = sheet.createRow(i);
            for (int j = 0; j < row.size(); j++) {
                if (patriarch != null && row.get(j) != null && row.get(j) instanceof URL) {
                    URL url = (URL)row.get(j);
                    sr.setHeight((short)(IMG_HEIGTH * IMG_WIDTH));
                    drawPictureIntoExcel(book, patriarch, i, j, url);
                } else {
                    setExcelValue(sr.createCell(j), row.get(j), style);
                }
            }
        }
    }

    /**
     * Excel單行設置值通常用於合併單元格
     * @param row 行對象
     */
    public static void writeSingleRowExcel(Row row, List<Object> rowList, CellStyle style){
        if (row == null) {
            throw new NullPointerException("the HSSFRow is null");
        }
        if (PlatformUtils.isEmpty(rowList)) {
            return;
        }
        // 設置行數據
        for (int i = 0; i < rowList.size(); i++) {
            setExcelValue(row.createCell(i), rowList.get(i), style);
        }
    }

    /**
     * 將Excel轉化爲輸入流
     * @param book Excel對象
     * @return 輸入流
     * @throws IOException
     */
    public static InputStream sxssfWorkbookToInputStream(SXSSFWorkbook book) throws IOException {
        ByteArrayInputStream bais = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        book.write(baos);
        bais = new ByteArrayInputStream(baos.toByteArray());
        baos.close();
        book.close();
        return bais;
    }

    /**
     * 上傳臨時文件
     * @param url
     * @param fileName  文件名
     * @param is 文件輸入流
     * @return 文件返回路徑
     * @throws Exception
     */
    public static String uploadTempFile(String url, String fileName, InputStream is) throws Exception {
        HttpSocket socket = new HttpSocket();
        socket.setUrl(url);
        // 爲了能使用到華爲存儲的自動刪除功能, 將臨時文件所有放到comId=1的目錄下
        socket.addParameter(ConstBusiness.COM_ID, "1");
        socket.addParameter("savePath", ConfigManager.getInstance().getValue(PlatformConstant.class, PlatformConstant.PICTURE_SERVER_PATH));
        socket.addAttachment(fileName, fileName, "text/plain", is);
        socket.doPostMultipart();
        is.close();
        JSONObject result = JSONObject.fromObject(socket.getResponseData());
        if (result.getInt("code") > 0) {
            throw new RuntimeException(result.getString("msg"));
        }
        return result.getString("msg");
    }

    /**
     * Excel導出設置Workbook(包含下載圖片)
     * @param title 導出Excel文件名稱
     * @param rowList 第一個List爲表頭,其他行爲表數據
     * @param downLoadPic 是否下載圖片 (若是要下載圖片,圖片的信息放Excel維度的第一列)
     * @throws IOException
     */
    public static HSSFWorkbook wrapSingleWorkbook(String title,List<List<Object>> rowList, Boolean downLoadPic) throws IOException {
        String filename = title;
        if (!PlatformUtils.hasText(title)) {
            filename = new SimpleDateFormat("yyMMddHHmmss").format(new Date());
        }
        if (rowList == null || rowList.isEmpty()) {
            throw new NullPointerException("the row list is null");
        }
        HSSFWorkbook book = new HSSFWorkbook();
        // 建立表
        HSSFSheet sheet = book.createSheet(filename);
        // 設置單元格默認寬度爲15個字符
        sheet.setDefaultColumnWidth(15);
        HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
        // 設置表頭樣式
        HSSFCellStyle style = book.createCellStyle();
        // 設置居左
        style.setAlignment(HSSFCellStyle.ALIGN_LEFT);
        // 這種自動換行
        style.setWrapText(true);
        // 檢測表頭數據(表頭不容許數據爲空)
        List<Object> head = rowList.get(0);
        for (Object key : head) {
            if (!PlatformUtils.hasText(key.toString())) {
                book.close();
                throw new NullPointerException("there is a blank exist head row");
            }
        }
        // 寫數據
        int size = rowList.get(0).size();
        for (int i = 0; i < rowList.size(); i++) {
            List<Object> row = rowList.get(i);
            if (row == null || row.isEmpty()) {
                book.close();
                throw new NullPointerException("the "+(i+1)+"th row is null");
            }
            if (size != row.size()) {
                book.close();
                throw new IllegalArgumentException("the cell number of "+(i+1)+"th row is different form the first");
            }
            HSSFRow sr = sheet.createRow(i);
            for (int j = 0; j < row.size(); j++) {
                // 在每行的第一個單元格插入圖片
                if (downLoadPic && i > 0 && j == 0) {
                    sr.setHeight((short) (800));
                    drawPictureIntoExcel(book, patriarch, i, row.get(0).toString());
                } else {
                    HSSFCell cell = sr.createCell(j);
                    setExcelValue(cell, row.get(j), style);
                }
            }
        }
        return book;
    }

    /**將圖片寫入excel
     * @param wb
     * @param patriarch 
     * @param rowIndex 當前行數
     * @param pictureUrl 圖片連接
     * 
     */
    private static void drawPictureIntoExcel(HSSFWorkbook wb, HSSFPatriarch patriarch, int rowIndex, String pictureUrl) {
        try {
            if (PlatformUtils.hasText(pictureUrl)) {
                URL url = new URL(pictureUrl);
                // 打開連接
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                // 設置請求方式爲"GET"
                conn.setRequestMethod("GET");
                // 超時響應時間爲5秒
                conn.setConnectTimeout(5 * 1000);
                // 經過輸入流獲取圖片數據
                InputStream inStream = conn.getInputStream();
                // 獲得圖片的二進制數據,以二進制封裝獲得數據
                byte[] data = readInputStream(inStream);
                // anchor主要用於設置圖片的位置
                HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 0, 0, (short) 0, rowIndex, (short) 1, rowIndex+1);
                // Sets the anchor type (圖片在單元格的位置)
                // 0 = Move and size with Cells, 2 = Move but don't size with
                // cells, 3 = Don't move or size with cells.
                anchor.setAnchorType(3);
                patriarch.createPicture(anchor, wb.addPicture(data, HSSFWorkbook.PICTURE_TYPE_JPEG));
            }
        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

    private static byte[] readInputStream(InputStream inStream) throws Exception {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        // 建立一個Buffer字符串
        byte[] buffer = new byte[1024];
        // 每次讀取的字符串長度,若是爲-1,表明所有讀取完畢
        int len = 0;
        // 使用一個輸入流從buffer裏把數據讀取出來
        while ((len = inStream.read(buffer)) != -1) {
            // 用輸出流往buffer裏寫入數據,中間參數表明從哪一個位置開始讀,len表明讀取的長度
            outStream.write(buffer, 0, len);
        }
        // 關閉輸入流
        inStream.close();
        // 把outStream裏的數據寫入內存
        return outStream.toByteArray();
    }

}
相關文章
相關標籤/搜索