記錄一個jxl導出excel工具類

自定義註解

ExcelField

package com.hfepay.ai.platform.application.attend.annotation;

import java.lang.annotation.*;

/***
 * @ClassName: ExcelField
 * @Description: 導出註解
 * @Author: wm_yu
 * @Create_time: 9:46 2019-10-22
 */
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelField {
    /**
     * 標題行
     */
    String title();

    /**
     * 列排序
     */
    int order() default 0;

    /**
     * 標紅條件,大於改值
     */
    int colorInt() default -1;

    /**
     * 日期格式
     */
    String dateFormat() default "yyyy-MM-dd HH:mm:ss";

}

 

使用到的反射工具類:

package com.hfepay.ai.platform.application.attend.util;

import com.alibaba.druid.sql.visitor.functions.Char;
import com.hfepay.ai.platform.application.attend.annotation.ExcelField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/***
 * @ClassName: ClassReflectUtil
 * @Description: 反射工具類
 * @Author: wm_yu
 * @Create_time: 9:51 2019-10-22
 */
public class ClassReflectUtil {

    private final static Logger LOG = LoggerFactory.getLogger(ClassReflectUtil.class);

    private static final String ORDER_ARR = "order_arr";
    private static final String COLUMN_ARR = "column_arr";
    private static final String TITLE_ARR = "title_arr";

    /**
     * 根據註解獲取到標題行,有排序按照排序,否則默認定義的字段順序
     * @param clzz
     * @return
     */
    public static String[] getExcelTitle(Class<?> clzz){
        Map<String, Object> map = sort(clzz);
        return Optional.ofNullable(map).map(x -> (String[])x.get(TITLE_ARR)).orElse(new String[1]);
    }

    /**
     * 獲取導出列(已排序)
     * @param clzz
     * @return
     */
    public static String[] getColumns(Class<?> clzz){
        Map<String, Object> map = sort(clzz);
        return Optional.ofNullable(map).map(x -> (String[])x.get(COLUMN_ARR)).orElse(new String[1]);
    }

    /**
     * 根據註解ExcelField對字段進行排序,生成排序數組,標題數組,列名數組
     * @param clzz
     * @return
     */
    private static Map<String,Object> sort(Class clzz){
        Assert.notNull(clzz,"class can not be null....");
        Field[] fields = getAllFields(clzz);
        long count = Arrays.stream(fields).filter(x -> x.isAnnotationPresent(ExcelField.class)).count();
        //排序數組
        int[] orderArr = new int[(int)count];
        //嚴格和排序對應的標題數組
        String[] titleArr = new String[(int)count];
        //嚴格和排序對應的對象列名稱的數組
        String[] columnArr = new String[(int)count];

        int k = 0;
        for (Field field : fields) {
            if(field.isAnnotationPresent(ExcelField.class)){
                if(field.isAccessible()){
                    field.setAccessible(true);
                }
                ExcelField annotation = field.getAnnotation(ExcelField.class);
                orderArr[k] = annotation.order();
                titleArr[k] = annotation.title();
                columnArr[k] = field.getName();
                k ++;
            }
        }
        //排序
        for (int i = 0; i < orderArr.length; i++) {
            boolean flag = false;
            for (int j = 0; j < orderArr.length - i - 1; j++) {
                if(orderArr[j] > orderArr[j+1]){
                    int order = orderArr[j+1];
                    orderArr[j+1] = orderArr[j];
                    orderArr[j] = order;

                    String title = titleArr[j+1];
                    titleArr[j+1] = titleArr[j];
                    titleArr[j] = title;

                    String columnName = columnArr[j+1];
                    columnArr[j+1] = columnArr[j];
                    columnArr[j] = columnName;

                    flag = true;
                }
            }
            if(!flag){
                break;
            }
        }
       Map<String, Object> map = new HashMap<>(3);
        map.put(ORDER_ARR,orderArr);
        map.put(COLUMN_ARR,columnArr);
        map.put(TITLE_ARR,titleArr);
        return map;
    }

    /**
     * 獲取類所有字段(含超類字段)
     * @param c
     * @return
     */
    public static Field[] getAllFields(Class c){
        List<Field> fieldList = new ArrayList<>();
        while (c!= null){
            fieldList.addAll(new ArrayList<>(Arrays.asList(c.getDeclaredFields())));
            c= c.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        return fields;
    }

    /**
     * 給null值給定默認值,時間類型排除不處理
     */
    public static <T> void nullToDefaultValue(T obj){
        Assert.notNull(obj,"source can not be null.....");
        Field[] fields = ClassReflectUtil.getAllFields(obj.getClass());
        Arrays.stream(fields)
                .filter(x -> !Modifier.isFinal(x.getModifiers())
                && !Modifier.isStatic(x.getModifiers())
                &&!Modifier.isAbstract(x.getModifiers()))
                .forEach(x -> {
                    autoMatch(x,obj);
                });
    }

    /**
     * 類型匹配
     * @param x 字段Field
     * @param obj 對象
     * @param <T>
     */
    private static <T> void autoMatch(Field x,T obj){
        if(!x.isAccessible()){
            x.setAccessible(true);
        }
        try {
            Object o = x.get(obj);
            //null值處理
            if(ObjectUtils.isEmpty(o)){
                Class<?> type = x.getType();
                if(type == Date.class){
                    return;
                }
                if(type == String.class){
                    x.set(obj,"");
                }
                else if(type == Integer.class){
                    x.set(obj,0);
                }
                else if(type == Double.class){
                    x.set(obj,0.0D);
                }
                else  if(type == BigDecimal.class){
                    x.set(obj,new BigDecimal(0));
                }
                else if(type == Float.class){
                    x.set(obj,0.0f);
                }
                else if(type == Long.class){
                    x.set(obj,0L);
                }
                else if(type == HashMap.class){
                    x.set(obj,new HashMap<>(1));
                }
                else if(type == Boolean.class){
                    x.set(obj,false);
                }
                else  if(type == Short.class){
                    x.set(obj,0);
                }
                else if(type == Char.class){
                    x.set(obj,0);
                }
                else if(type == Byte.class){
                    x.set(obj,0);
                }
                else  if(type == ConcurrentMap.class){
                    x.set(obj,new ConcurrentHashMap<>(1));
                }
                else if(type.isArray()){
                    Object[] arr = {};
                    x.set(obj,arr);
                } else if(type == List.class){
                    x.set(obj,Collections.EMPTY_LIST);
                }else{
                    Object var = x.getType().newInstance();
                    x.set(obj,var);
                }
            }
        } catch (IllegalAccessException | InstantiationException e) {
            LOG.error("對象屬性:{} 不能通過反射獲取到值",x.toGenericString(),e.getMessage(),e);
        }
    }
}

 

excel導出工具類:excelUtil.java

package com.hfepay.ai.platform.application.attend.util.excel;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.hfepay.ai.platform.application.attend.annotation.ExcelField;
import com.hfepay.ai.platform.application.attend.util.ClassReflectUtil;
import com.hfepay.common.util.DateUtils;
import jxl.Workbook;
import jxl.write.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/***
 * @ClassName: ExcelUtil
 * @Description: 導出工具類
 * @Author: wm_yu
 * @Create_time: 15:25 2019-10-22
 */
public class ExcelUtil {

    private final static Logger LOG = LoggerFactory.getLogger(ExcelUtil.class);

    /**
     * excel單元格寬度,默認爲20
     */
    private static int width = 20;

    /**
     * 導出excel文件,瀏覽器直接下載
     * @param response response流
     * @param dataList 填充的數據集合,需要指定泛型
     * @param sheetName sheet名稱
     * @param fileName  下載的文件名稱
     * @param bigTitle 大標題行,限定爲第一行
     * @param <T>
     */
    public static <T> void excelExport(HttpServletResponse response,List<T> dataList,String sheetName,String fileName,String bigTitle){
        if(CollectionUtils.isEmpty(dataList)){
            return;
        }
        Class<?> clzz = dataList.get(0).getClass();
        //屬性集合
        Field[] fields = ClassReflectUtil.getAllFields(clzz);
        List<Field> fieldList = Arrays.stream(fields).filter(x -> x.isAnnotationPresent(ExcelField.class)).collect(Collectors.toList());
        //維護列名稱和對應的索引,填充cell使用
        Map<String, Integer> map = new ConcurrentHashMap<>();
        /**
         * 列名稱數組
         */
        String[] columnArr = ClassReflectUtil.getColumns(clzz);
        /**
         * 標題行數組
         */
        String[] titleArr = ClassReflectUtil.getExcelTitle(clzz);
        //構建map
        for (int i = 0; i < columnArr.length; i++) {
            map.put(columnArr[i],i);
        }
        ServletOutputStream os = null;
        try {
            os = response.getOutputStream();
            //創建workbook,sheet
            WritableWorkbook workbook = Workbook.createWorkbook(response.getOutputStream());
            //第一個sheet
            WritableSheet sheet = workbook.createSheet(sheetName, 0);
            //固定大小標題行
            sheet.getSettings().setVerticalFreeze(1);
            sheet.getSettings().setVerticalFreeze(2);
           //初始化樣式
            List<WritableCellFormat> styleList = initStyleFormat();
            //構建大標題行,需要合併單元格  合併單元格,參數依次爲:列索引、行索引、列索引+需要合併的列的個數、行索引+需要合併的行的個數
            sheet.mergeCells(0,0,columnArr.length - 1,0);
            Label bigLabel = new Label(0, 0, bigTitle, styleList.get(0));
            sheet.addCell(bigLabel);

            for (int i = 0; i < titleArr.length; i++) {
                Label excelTitle = new Label(i, 1, titleArr[i], styleList.get(0));
                sheet.addCell(excelTitle);
                // 設置列寬
                sheet.setColumnView(i, width);
            }
            /*****************填充數據*********************/
            //數據行從第三行開始,第一行爲大標題行,第二行爲小標題行
            int rowIndex = 2;
            for (T data : dataList) {
                //循環field
                for (Field field : fieldList) {
                    if(!field.isAccessible()){
                        field.setAccessible(true);
                    }
                    //判斷是否需要標紅數據
                    String dateFormat = field.getAnnotation(ExcelField.class).dateFormat();
                    int colorInt = field.getAnnotation(ExcelField.class).colorInt();
                    Object o = field.get(data);
                     Label label = null;
                    if(!ObjectUtils.isEmpty(o)){
                        if(o instanceof String){
                            //創建單元格,正常樣式
                            label = new Label(map.get(field.getName()), rowIndex,(String) o,styleList.get(1));
                        }
                        else if(o instanceof Integer){
                            //排除默認值
                            if((Integer)o > colorInt && colorInt != -1){
                                //數據標紅
                                label = new Label(map.get(field.getName()),rowIndex, String.valueOf(o),styleList.get(2));
                            }else{
                              label = new Label(map.get(field.getName()),rowIndex, String.valueOf(o),styleList.get(1));
                            }
                        }
                        else if(o instanceof Date){
                            label = new Label(map.get(field.getName()),rowIndex, DateUtils.format((Date) o,dateFormat),styleList.get(1));
                        }else {
                            label = new Label(map.get(field.getName()), rowIndex,String.valueOf(o),styleList.get(1));
                        }
                    //添加到行中
                    sheet.addCell(label);
                    }
                }
                ++ rowIndex;
            }
            /*****************填充數據*********************/
            //導出excel
            // 處理中文的文件名
            String fileNameCN = new String(fileName.getBytes("utf-8"),
                    "ISO-8859-1");
            response.reset();
            // 保存爲excel
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            response.addHeader("Content-Disposition", "attachment;filename="
                    + fileNameCN);
            workbook.write(); // 寫入到os流中
            workbook.close();
            os.flush();
            os.close();
        } catch (Exception e) {
            LOG.error("導出excel異常:{}",e.getMessage(),e);
        }
     }



    /**
     * 初始化樣式
     * @return
     * @throws Exception
     */
    private static List<WritableCellFormat> initStyleFormat() throws Exception{
        // 列標題字體
        WritableFont wfont = new WritableFont(WritableFont.ARIAL, 16,WritableFont.BOLD, false,jxl.format.UnderlineStyle.NO_UNDERLINE,jxl.format.Colour.BLACK);
        // 列標題字體 綠色
        WritableFont wfontGreenTitle = new WritableFont(WritableFont.ARIAL, 16,WritableFont.BOLD, false,jxl.format.UnderlineStyle.NO_UNDERLINE,jxl.format.Colour.GREEN);
        // 正常字體
        WritableFont wfont2 = new WritableFont(WritableFont.ARIAL, 10,WritableFont.NO_BOLD, false,jxl.format.UnderlineStyle.NO_UNDERLINE,jxl.format.Colour.BLACK);
        // 正常字體,標紅
        WritableFont wfontRed = new WritableFont(WritableFont.ARIAL, 10,WritableFont.NO_BOLD, false,jxl.format.UnderlineStyle.NO_UNDERLINE,jxl.format.Colour.RED);
        // 正常字體,綠色
        WritableFont wfontGreen = new WritableFont(WritableFont.ARIAL, 10,WritableFont.NO_BOLD, false,jxl.format.UnderlineStyle.NO_UNDERLINE,jxl.format.Colour.GREEN);

        WritableCellFormat titleFormat = new WritableCellFormat(wfont);
        titleFormat.setVerticalAlignment(VerticalAlignment.CENTRE);
        titleFormat.setAlignment(Alignment.CENTRE);
        //給單元格加邊框
        titleFormat.setBorder(jxl.format.Border.ALL,jxl.format.BorderLineStyle.THIN);

        WritableCellFormat generalFormat = new WritableCellFormat(wfont2);
        generalFormat.setVerticalAlignment(VerticalAlignment.CENTRE);
        generalFormat.setAlignment(Alignment.CENTRE);
        //給單元格加邊框
        generalFormat.setBorder(jxl.format.Border.ALL,jxl.format.BorderLineStyle.THIN);

        WritableCellFormat redFormat = new WritableCellFormat(wfontRed);
        redFormat.setVerticalAlignment(VerticalAlignment.CENTRE);
        redFormat.setAlignment(Alignment.CENTRE);
        redFormat.setBorder(jxl.format.Border.ALL,jxl.format.BorderLineStyle.THIN);

        WritableCellFormat greenFormat = new WritableCellFormat(wfontGreen);
        greenFormat.setVerticalAlignment(VerticalAlignment.CENTRE);
        greenFormat.setAlignment(Alignment.CENTRE);
        greenFormat.setBorder(jxl.format.Border.ALL,jxl.format.BorderLineStyle.THIN);

        WritableCellFormat greenTitleFormat = new WritableCellFormat(wfontGreenTitle);
        greenTitleFormat.setVerticalAlignment(VerticalAlignment.CENTRE);
        greenTitleFormat.setAlignment(Alignment.CENTRE);
        greenFormat.setBorder(jxl.format.Border.ALL,jxl.format.BorderLineStyle.THIN);

        List<WritableCellFormat> list = new ArrayList<WritableCellFormat>(){{
            add(titleFormat);
            add(generalFormat);
            add(redFormat);
            add(greenFormat);
            add(greenTitleFormat);
        }};
        return list;
    }

















    }


 

 

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