通用的jxl導(dǎo)出Excel文件

效果圖

image.png

引入依賴

<dependency>
       <groupId>net.sourceforge.jexcelapi</groupId>
       <artifactId>jxl</artifactId>
       <version>2.6.12</version>
</dependency>

實(shí)現(xiàn)類

package 你自己的包路徑;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 抽象接口,為擴(kuò)展poi和jxl等其他導(dǎo)出技術(shù)
 * 設(shè)計(jì)模式:模板模式
 */
public interface ExcelTemplate<T> {

    /**
     * 序號(hào)計(jì)數(shù)器
     */
    AtomicInteger COUNTER = new AtomicInteger(0);

    /**
     * 抽象模板方法
     * @param fileName 導(dǎo)出的文件名
     * @param exportList 導(dǎo)出的數(shù)據(jù)集合
     */
    void execute(String fileName, List<T> exportList);

    /**
     * 接口默認(rèn)實(shí)現(xiàn)方法缔御,獲取反射類字段
     * @param fieldName 字段名
     * @param clazz 反射類
     * @return 字段信息
     */
    default Field getField(String fieldName, Class<?> clazz){
        Field field = null;
        try {
            field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        return field;
    }

    /**
     * 接口默認(rèn)實(shí)現(xiàn)方法,獲取反射類字段值
     * @param fieldName 字段名
     * @param clazz 反射類
     * @return 字段值
     */
    default String getFieldVal(Field field, Class<?> clazz, String fieldName, Object obj) {
        String getField = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        String fieldType = field.getGenericType().getTypeName();
        ExportField fieldAnnotation = field.getAnnotation(ExportField.class);
        String defaultDateFormat = "yyyy-MM-dd HH:mm:ss";
        if (fieldAnnotation != null){
            if (fieldAnnotation.isNo()){
                return String.valueOf(COUNTER.addAndGet(1));
            }
            defaultDateFormat = fieldAnnotation.dateFormat();
        }

        Method method = null;
        try {
            method = clazz.getMethod("get" + getField);
        } catch (NoSuchMethodException e) {

            //基本類型,boolean等贷盲,生成的是isXXX坏匪,也可以再捕獲一下獲取
            /*try {
                method = clazz.getMethod("is" + getField);
            } catch (NoSuchMethodException e1) {
                e1.printStackTrace();
            }*/
            throw new NullPointerException("請將類中獲取屬性的方法使用get開始");
        }

        if (method == null){
            return null;
        }

        Object invoke = null;
        try {
            method.setAccessible(true);
            invoke = method.invoke(obj);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        if (invoke == null){
            return null;
        }

        if (StringUtils.isNotEmpty(fieldType)){
            switch (fieldType){
                case "java.util.Date":
                    return DateFormatUtils.format((Date) invoke, defaultDateFormat);
                case "java.sql.Clob":
                    return "自定義處理即可";
            }
        }

        return invoke.toString();
    }

}

package 你自己的包路徑;

import jxl.Workbook;
import jxl.format.*;
import jxl.format.Alignment;
import jxl.format.Border;
import jxl.format.BorderLineStyle;
import jxl.format.Colour;
import jxl.format.VerticalAlignment;
import jxl.write.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;

/**
 * jxl導(dǎo)出excel文件
 * @Author: lilin
 * @Date: 2022/1/24
 */
public class JxlExcelTemplate<T> implements ExcelTemplate<T>{

    /** 多行標(biāo)題最長的一列拟逮,用來計(jì)算其他標(biāo)題行合并 */
    private Integer titleMaxLen;

    /** 標(biāo)題 */
    private String[][] title;

    /** 數(shù)據(jù)遍歷起始行,首行一般為標(biāo)題适滓,例如:標(biāo)題行占了3敦迄,就要從4開始創(chuàng)建行數(shù)據(jù) */
    private Integer startIndex;

    private WritableSheet sheet;
    private HttpServletResponse response;
    private WritableWorkbook workbook;

    /** 單元格默認(rèn)寬度 */
    private static Integer DEFAULT_WIDTH = 12;

    /**
     * 構(gòu)造器
     * @param title 標(biāo)題行
     * @param sheetName sheet名稱
     * @param response 響應(yīng)
     */
    public JxlExcelTemplate(String[][] title, String sheetName, HttpServletResponse response) {
        try {
            this.title = title;
            this.startIndex = this.title == null ? null : this.title.length;
            ServletOutputStream ops = response.getOutputStream();
            workbook = Workbook.createWorkbook(ops);
            sheet = workbook.createSheet(sheetName, 0);
            this.title = title;
            this.response = response;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 標(biāo)題行初始化 + 合并
     * @throws Exception
     */
    private void titleInit() throws Exception {
        if (this.title == null || this.title.length == 0){
            throw new NullPointerException("title can not null");
        }

        if (titleMaxLen == null){
            titleMaxLen = 0;
        }

        for (String[] t1 : title) {
            int length = t1.length;
            titleMaxLen = Math.max(length, titleMaxLen);
        }

        for (int i = 0; i < title.length; i++) {
            String[] t2 = title[i];
            for (int j = 0; j < t2.length; j++) {
                if (t2.length == 1){
                    sheet.addCell(new Label(j, i, t2[j], buildTitleStyle()));
                    sheet.mergeCells(i, j, titleMaxLen - 1, j);
                }else {
                    sheet.addCell(new Label(j, i, t2[j], buildTitleStyle()));
                }
            }
        }
    }

    protected CellFormat buildTitleStyle(){
        WritableCellFormat wcfFC = new WritableCellFormat();
        try {
            wcfFC.setVerticalAlignment(VerticalAlignment.CENTRE);
            wcfFC.setAlignment(Alignment.CENTRE);
            wcfFC.setBorder(Border.ALL, BorderLineStyle.THIN);
            wcfFC.setBackground(Colour.ORANGE);
        } catch (WriteException e) {
            e.printStackTrace();
        }
        return wcfFC;
    }

    protected WritableCellFormat buildColumStyle() {
        WritableCellFormat wcfFC = new WritableCellFormat();
        try {
            wcfFC.setVerticalAlignment(VerticalAlignment.CENTRE);
            wcfFC.setAlignment(Alignment.LEFT);
            wcfFC.setBorder(Border.ALL, BorderLineStyle.THIN);
        } catch (WriteException e) {
            e.printStackTrace();
        }
        return wcfFC;
    }

    /**
     * 可重寫的導(dǎo)出數(shù)據(jù)表格
     */
    protected void buildList(List<T> list, WritableSheet sheet, Integer startIndex, String... showFiles){
        try {
            int i = startIndex;
            for (T t : list) {
                Class<?> clazz = t.getClass();

                int j = 0;
                for (String showFile : showFiles) {
                    int width = DEFAULT_WIDTH;
                    Field field = getField(showFile, clazz);
                    String fieldVal = getFieldVal(field, clazz, showFile, t);

                    ExportField fieldAnnotation = field.getAnnotation(ExportField.class);
                    if (fieldAnnotation != null){
                        width = fieldAnnotation.width();
                    }

                    sheet.addCell(new Label(j, i, fieldVal, buildColumStyle()));
                    sheet.setColumnView(j, width);
                    j++;
                }
                i++;
            }
        } catch (WriteException e) {
            e.printStackTrace();
        }
    }

    private void exportList(String fileName) throws Exception{
        response.reset();
        response.setContentType("application/json;charset=utf-8");
        response.setHeader("Content-disposition", "attachment; filename="+ new String((fileName).getBytes("gbk"),"iso8859-1") +".xls");// 設(shè)定輸出文件頭

        BufferedOutputStream bufferedOutPut = null;
        ServletOutputStream output = null;
        try {
            output = response.getOutputStream();
            bufferedOutPut = new BufferedOutputStream(output);
            bufferedOutPut.flush();
            workbook.write();
            workbook.close();
        } catch (IOException e){
            e.printStackTrace();
        } finally{
            if (bufferedOutPut != null){
                try {
                    bufferedOutPut.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (output != null){
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void execute(String fileName, List<T> exportList){
        try {
            titleInit();
            buildList(exportList, sheet, startIndex);
            exportList(fileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void execute(String fileName, List<T> exportList, String... showFiles){
        try {
            titleInit();
            buildList(exportList, sheet, startIndex, showFiles);
            exportList(fileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

定義注解,方便控制各項(xiàng)屬性

package 你自己的包路徑;

import java.lang.annotation.*;
import java.util.Map;


/**
 * 導(dǎo)出信息配置注解
 * @author 李林
 * @date 2022-01-22
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExportField {

    /**
     * 是否為序號(hào)字段
     * 為了應(yīng)對導(dǎo)出需要從1開始計(jì)數(shù)凭迹,默認(rèn)不需要
     */
    boolean isNo() default false;

    /**
     * 暫時(shí)沒用罚屋,作為標(biāo)記
     * 單元格頂部標(biāo)題,當(dāng)只需要一層標(biāo)題的時(shí)候嗅绸,僅加入此項(xiàng)配置即可脾猛,就不需要傳二維數(shù)組的標(biāo)題了
     */
    String fieldName() default "";

    /**
     * 默認(rèn)單元格寬度,256為一個(gè)字節(jié)寬度
     */
    int width() default 18;

    /**
     * 當(dāng)字段為日期類型時(shí),希望的轉(zhuǎn)換格式
     */
    String dateFormat() default "yyyy-MM-dd HH:mm:ss";
}

隨便定義個(gè)類鱼鸠,作為數(shù)據(jù)庫查詢返回實(shí)體類

package 你自己的包路徑;

import com.erhya.admin.service.poi.ExportField;
import lombok.Data;

import java.math.BigDecimal;

@Data
public class H33ExportDTO {

    /**
     * 訂單編號(hào)
     */
    private String orderNo;

    /**
     * 買家會(huì)員名
     */
    private String vipName;

    /**
     * 買家支付寶賬號(hào)
     */
    @ExportField(width = 30)
    private String zhiPayAccount;

    /**
     * 總金額
     */
    private BigDecimal amount;

    /**
     * 訂單狀態(tài)
     */
    private String orderStatus;

    /**
     * 收貨人姓名
     */
    private String userName;

    /**
     * 收貨地址
     */
    @ExportField(width = 30)
    private String userAddr;

    /**
     * 聯(lián)系手機(jī)
     */
    private String mobile;

    /**
     * 訂單時(shí)間
     */
    @ExportField(width = 22)
    private String orderTime;

    /**
     * 寶貝標(biāo)題
     */
    @ExportField(width = 100)
    private String title;

}

調(diào)用測試類猛拴,controller:http://localhost:port/項(xiàng)目名/buildTest/100

@GetMapping("buildTest/{dataCount}")
    public void buildTest(@PathVariable Integer dataCount, HttpServletResponse response){
        List<H33ExportDTO> h33ExportDTOS = new ArrayList<>();
        H33ExportDTO data = null;
        for (int i = 0; i < dataCount; i++) {
            data = new H33ExportDTO();
            data.setOrderNo(DateFormatUtils.format(new Date(), "yyyyMMddHHmmssS"));
            data.setVipName("小明");
            data.setZhiPayAccount("zhifu"+RandomUtils.nextInt(1000, 100000));
            data.setMobile("15168455555");
            data.setOrderStatus("正常");
            data.setUserName("派大星");
            data.setUserAddr("比奇堡分堡,XX座蚀狰,X幢X單元1205");
            data.setOrderTime(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
            data.setTitle("飛利浦白色大平板開關(guān)插座家用墻壁86型暗裝五孔帶USB面板燈開關(guān)愉昆,家裝三年質(zhì)保");
            data.setAmount(new BigDecimal(RandomUtils.nextDouble(50, 10000d)));
            h33ExportDTOS.add(data);
        }


        String[][] title = {{"比奇堡物流信息"},{"訂單編號(hào)", "買家會(huì)員名", "買家支付寶賬號(hào)", "總金額", "訂單狀態(tài)", "收貨人姓名", "收貨地址", "聯(lián)系手機(jī)", "訂單付款時(shí)間", "寶貝標(biāo)題"}};
        
        PoiExcelTemplate<H33ExportDTO> commonTemplateAbstract = new PoiExcelTemplate<>(title, null, response);
        commonTemplateAbstract.execute( "自定義文件名_" + DateFormatUtils.format(new Date(), "yyyyMMddHHmmss"),
                h33ExportDTOS, "orderNo","vipName","zhiPayAccount","amount","orderStatus","userName","userAddr","mobile","orderTime","title");

    }

另一篇:通用poi導(dǎo)出excel文件

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市麻蹋,隨后出現(xiàn)的幾起案子跛溉,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芳室,死亡現(xiàn)場離奇詭異专肪,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)堪侯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門嚎尤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人抖格,你說我怎么就攤上這事诺苹。” “怎么了雹拄?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵收奔,是天一觀的道長。 經(jīng)常有香客問我滓玖,道長坪哄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任势篡,我火速辦了婚禮翩肌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘禁悠。我一直安慰自己念祭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布碍侦。 她就那樣靜靜地躺著粱坤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瓷产。 梳的紋絲不亂的頭發(fā)上站玄,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機(jī)與錄音濒旦,去河邊找鬼株旷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛尔邓,可吹牛的內(nèi)容都是我干的晾剖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼铃拇,長吁一口氣:“原來是場噩夢啊……” “哼钞瀑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起慷荔,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后显晶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贷岸,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年磷雇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了偿警。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡唯笙,死狀恐怖螟蒸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情崩掘,我是刑警寧澤七嫌,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站苞慢,受9級(jí)特大地震影響诵原,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜挽放,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一绍赛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧辑畦,春花似錦吗蚌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至潦刃,卻和暖如春侮措,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背乖杠。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工分扎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人胧洒。 一個(gè)月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓畏吓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親卫漫。 傳聞我的和親對象是個(gè)殘疾皇子菲饼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容