JXLS (excel报表生成/导出工具)的配置与使用

JXLS(excel报表生成工具)的配置与使用

  1. 什么是jxls
    JXLS 是基于 Jakarta POI API 的 Excel 报表生成工具,可以生成精美的 Excel 格式报表。它采用标签的方式,类似 JSP 标签,写一个 Excel 模板,然后生成报表,非常灵活,简单!
  2. 为什么用jxls
    Java 有一些用于创建 Excel 文件的库,例如 Apache POI。这些库很棒,但是级别很低,因为它们要求开发人员甚至创建一个简单的 Excel 文件也要编写很多 Java 代码。通常,必须手动设置电子表格的每个单元格格式和数据。根据报表布局和数据格式的复杂性,Java 代码可能变得非常复杂,并且难以调试和维护。此外,并非所有 Excel 功能都受支持,并且可以使用库 API 进行操作(例如,对宏,图形等的有限支持)。对于不受支持的功能,建议的解决方法是在 Excel 模板中手动创建对象,然后在模板中填充数据。
    Jxls 将这种方法带入了更高的层次。使用 Jxls 时,只需要在 Excel 模板文件中定义所需的报告格式和数据布局,然后运行 Jxls 引擎以用数据填充模板。开发人员只需编写少量 Java 代码即可触发 Jxls 引擎对模板的处理。
  3. 配置与使用
    3.1 配置(按需要选择配置文件配置)
    3.1.1 引入依赖
           org.jxls
           jxls
           2.4.5
       
       
           org.jxls
           jxls-poi
           1.0.9
       
       
           org.jxls
           jxls-jexcel
           1.0.7
       

3.1.2 生成excel的工具类/工具辅助类
jxls工具辅助类

/**
 * 工具辅助类
 */
public class JxlsUtil {
    private static final JxlsUtil me = new JxlsUtil();

    private JxlsUtil() {

    }

    /**
     * 获取工具类实例
     *
     * @return
     */
    public static JxlsUtil me() {
        return me;
    }

    /**
     * 如果字符串为{@code null}、空字符串或仅包含空白字符, 则返回false
     *
     * @param text 要进行检查的字符串
     */
    public boolean hasText(String text) {
        return !(text == null || text.length() == 0);

    }

    /**
     * 如果数组为{@code null}或长度为0, 则返回false
     *
     * @param array 要进行检查的数组
     */
    public  boolean notEmpty(T[] array) {
        return !(array == null || array.length == 0);
    }

    /**
     * 如果数组里包含有{@code null}的元素, 则抛出异常. 注意: 若数组本身为{@code null}则不会进行处理, 直接返回false
     *
     * @param array 要进行检查的数组
     */
    public  boolean noNullElements(T[] array) {
        if (array != null) {
            for (T element : array) {
                if (element == null) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 如果集合为{@code null},或者不包含任何元素,则返回false
     *
     * @param collection 要进行检查的集合
     */
    public boolean notEmpty(Collection collection) {
        return !(collection == null || collection.isEmpty());
    }

    /**
     * 如果键值对为{@code null},或者不包含任何键值,则返回false
     *
     * @param map 要进行检查的键值对
     */
    public boolean notEmpty(Map map) {
        return !(map == null || map.isEmpty());
    }

    /**
     * 日期格式化
     *
     * @param date
     * @param fmt
     * @return
     */
    public String dateFmt(Date date, String fmt) {
        if (date == null) {
            return null;
        }
        try {
            SimpleDateFormat dateFmt = new SimpleDateFormat(fmt);
            return dateFmt.format(date);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 数字格式化
     *
     * @param number
     * @param format
     * @return
     */
    public String numFmt(Number number, String format) {
        DecimalFormat dFormat = new DecimalFormat(format);
        return dFormat.format(number);
    }

    /**
     * 返回第一个不为空的对象
     *
     * @param objs
     * @return
     */
    public Object getNotNull(Object... objs) {
        for (Object o : objs) {
            if (o != null) {
                return o;
            }
        }
        return null;
    }

    /**
     * if判断
     *
     * @param b
     * @param o1
     * @param o2
     * @return
     */
    public Object ifelse(boolean b, Object o1, Object o2) {
        return b ? o1 : o2;
    }

    /**
     * 将图片转成数据
     *
     * @param path 图片绝对路径
     * @return
     */
    public byte[] getImageData(String path) throws IOException {
        try (InputStream ins = new FileInputStream(path)) {
            return IOUtils.toByteArray(ins);
        }
    }

    /**
     * 获取图片后缀
     *
     * @param name 图片路径或名称
     * @return
     */
    public String getImageType(String name) {
        int index = name.lastIndexOf(".");
        if (index > 0) {
            return name.substring(index + 1);
        }
        return null;
    }

    /**
     * 将图片转成JxlsImage数据对象
     *
     * @param imgPath 图片路径
     * @return
     */
    public JxlsImage getJxlsImage(String imgPath) throws IOException {
        JxlsImage img = new JxlsImage();
        img.setPictureData(getImageData(imgPath));
        img.setPictureType(getImageType(imgPath));
        return img;
    }


    /**
     * 将图片转成JxlsImage数据对象
     * @param is
     * @param name
     * @return
     * @throws IOException
     */
    public JxlsImage getJxlsImage(InputStream is, String name) throws IOException {
        JxlsImage img = new JxlsImage();
        img.setPictureData(IOUtils.toByteArray(is));
        img.setPictureType(getImageType(name));
        return img;
    }
    
    /**
     * 判断路径是否是绝对路径
     *
     * @param path
     * @return
     */
    public boolean isAbsolutePath(String path) {
        return (path.startsWith("/") || path.contains(":"));
    }

    /**
     * 获取集合中的元素
     *
     * @param index
     * @param array
     * @return
     */
    public T get(int index, T[] array) {
        if (notEmpty(array)) {
            return array[index];
        }
        return null;
    }

    /**
     * 获取集合中的元素
     *
     * @param index
     * @param list
     * @return
     */
    public Object get(int index, List list) {
        if (notEmpty(list)) {
            return list.get(index);
        }
        return null;
    }

    /**
     * 获取集合中的元素
     *
     * @param key
     * @param map
     * @return
     */
    public Object get(Object key, Map map) {
        if (notEmpty(map)) {
            return map.get(key);
        }
        return null;
    }
}

jxsl配置类

public class JxlsConfig {
    /** 模板存放目录 */
    private static String templateRoot;
    /** 默认图片目录 */
    private static String imageRoot;
    /** 忽略warn警告 */
    private static boolean silent = false;
    /** 锁住配置 */
    private static boolean lock = false;

    static{
        JxlsConfig.config()
                //锁住配置,不能再修改
//                .lock()
                //设置模板文件根目录
//                .templateRoot("jxls_templates")
                .templateRoot("excel")
                //设置图片路径根目录
                .imageRoot("jxls_images");
    }

    private JxlsConfig(){ }

    public static JxlsConfig config(){
        if(lock){
            throw new IllegalArgumentException("jxls配置已设置锁住,不能再修改");
        }
        return new JxlsConfig();
    }

    public JxlsConfig templateRoot(String templateRoot) {
        JxlsConfig.templateRoot = getRealPath(templateRoot);
        return this;
    }

    public JxlsConfig imageRoot(String imageRoot) {
        JxlsConfig.imageRoot = getRealPath(imageRoot);
        return this;
    }

    public JxlsConfig silent(boolean silent) {
        JxlsConfig.silent = silent;
        return this;
    }

    public JxlsConfig lock() {
        JxlsConfig.lock = true;
        return this;
    }

    private String getRealPath(String originalPath){
        if(!JxlsUtil.me().isAbsolutePath(originalPath) && !originalPath.startsWith("classpath:/")){
            URL resource = JxlsConfig.class.getClassLoader().getResource(originalPath);
            if(resource != null){
                String path = resource.getPath();
                if(path.contains(".jar")){
                    int index = path.lastIndexOf("/", path.indexOf("!/BOOT-INF"));
                    path = path.substring(0, index).replaceFirst("file:/", "");
                    File file = new File(path + "/" + originalPath);
                    if(file.exists()){
                        return file.getAbsolutePath();
                    }
                    originalPath = "classpath:/" + originalPath;
                } else {
                    originalPath = path;
                }
            }
        }
        return originalPath;
    }

    public static String getTemplateRoot() {
        return templateRoot;
    }

    public static String getImageRoot() {
        return imageRoot;
    }

    public static boolean getSilent() {
        return silent;
    }
}

jxls生成excel辅助类

public abstract class JxlsBuilder {
    public static final String EXCEL_SUFFIX = ".xls";

    static {
        //注册 jx 命令
        XlsCommentAreaBuilder.addCommandMapping("merge", MergeCommand.class);
        XlsCommentAreaBuilder.addCommandMapping("image", ImageCommand.class);
        XlsCommentAreaBuilder.addCommandMapping("keep", KeepCommand.class);
        XlsCommentAreaBuilder.addCommandMapping("grid", GridCommand.class);
    }

    private JxlsHelper jxlsHelper = JxlsHelper.getInstance();

    private Transformer transformer;
    private Context context;
    private InputStream in;
    private OutputStream out;
    private File inFile;
    private File outFile;
    private Map funcs;
    private String imageRoot = JxlsConfig.getImageRoot();
    private boolean ignoreImageMiss = false;
    private String[] removeSheetNames;

    private JxlsBuilder() {
        context = new Context();
        funcs = new HashMap<>();
        funcs.put("jxu", JxlsUtil.me());
    }

    private JxlsBuilder(InputStream in) {
        this();
        this.in = in;
    }

    private JxlsBuilder(File inFile) {
        this();
        if (!inFile.exists()) {
            throw new IllegalArgumentException("模板文件不存在:" + inFile.getAbsolutePath());
        }
        if (!inFile.getName().toLowerCase().endsWith("xls") &&
                !inFile.getName().toLowerCase().endsWith("xlsx")) {
            throw new IllegalArgumentException("不支持非excel文件:" + inFile.getName());
        }
        this.inFile = inFile;
        try {
            in = new FileInputStream(inFile);
        } catch (FileNotFoundException e) {
            throw new IllegalArgumentException("文件读取失败:" + inFile.getAbsolutePath(), e);
        }
    }

    /**
     * @param in 模板文件流
     * @return
     */
    public static JxlsBuilder getBuilder(InputStream in) {
        return new JxlsBuilderImpl(in);
    }

    /**
     * @param templateFile 模板文件地址
     * @return
     */
    public static JxlsBuilder getBuilder(File templateFile) {
        return new JxlsBuilderImpl(templateFile);
    }

    /**
     * @param filePath 模板文件路径,可以是绝对路径,也可以是模板存放目录的文件名
     * @return
     */
    public static JxlsBuilder getBuilder(String filePath) {
        //判断是相对路径还是绝对路径
        if (!JxlsUtil.me().isAbsolutePath(filePath)) {
            if (JxlsConfig.getTemplateRoot().startsWith("classpath:")) {
                //文件在jar包内
                String templateRoot = JxlsConfig.getTemplateRoot().replaceFirst("classpath:", "");
                InputStream resourceAsStream = JxlsBuilder.class.getResourceAsStream(templateRoot + "/" + filePath);
                return new JxlsBuilderImpl(resourceAsStream);
            } else {
                //相对路径就从模板目录获取文件
                return new JxlsBuilderImpl(new File(JxlsConfig.getTemplateRoot() +
                        File.separator + filePath));
            }
        } else {
            //绝对路径
            return new JxlsBuilderImpl(new File(filePath));
        }
    }

    public JxlsHelper getJxlsHelper() {
        return jxlsHelper;
    }

    /**
     * 生成excel文件
     *
     * @return
     * @throws Exception
     */
    public JxlsBuilder build() throws Exception {
        getTransformer();

        if (JxlsUtil.me().hasText(imageRoot)) {
            context.putVar("_imageRoot", imageRoot);
        }
        context.putVar("_ignoreImageMiss", ignoreImageMiss);
        JexlExpressionEvaluator evaluator = (JexlExpressionEvaluator) jxlsHelper.createExpressionEvaluator(null);
        evaluator.getJexlEngine().setFunctions(funcs);
        evaluator.getJexlEngine().setSilent(JxlsConfig.getSilent());
        transform();
        return this;

    }

    private void transform() throws Exception {
        jxlsHelper.getAreaBuilder().setTransformer(transformer);
        List xlsAreaList = jxlsHelper.getAreaBuilder().build();
        Iterator var4 = xlsAreaList.iterator();

        while (var4.hasNext()) {
            Area xlsArea = (Area) var4.next();
            xlsArea.applyAt(new CellRef(xlsArea.getStartCellRef().getCellName()), context);
            if (jxlsHelper.isProcessFormulas()) {
                FormulaProcessor fp;
                if (jxlsHelper.isUseFastFormulaProcessor()) {
                    fp = new FastFormulaProcessor();
                } else {
                    fp = new StandardFormulaProcessor();
                }
                xlsArea.setFormulaProcessor(fp);
                xlsArea.processFormulas();
            }
        }
        if (JxlsUtil.me().notEmpty(removeSheetNames)) {
            for (String sheetName : removeSheetNames) {
                transformer.deleteSheet(sheetName);
            }
        }
        transformer.deleteSheet("Sheet");
        transformer.write();
    }

    private static class JxlsBuilderImpl extends JxlsBuilder {
        public JxlsBuilderImpl(InputStream in) {
            super(in);
        }

        public JxlsBuilderImpl(File inFile) {
            super(inFile);
        }
    }

    public Transformer getTransformer() throws Exception {
        if (transformer == null) {
            if (out == null && outFile == null) {
                throw new Exception("请指定文件输出位置");
            }
            if (out == null) {
                out = new FileOutputStream(outFile);
            }
            transformer = jxlsHelper.setUseFastFormulaProcessor(false).createTransformer(in, out);
//            transformer = jxlsHelper.setUseFastFormulaProcessor(true).createTransformer(in, out);
        }
        return transformer;
    }

    /**
     * 指定输出流
     *
     * @param out
     * @return
     */
    public JxlsBuilder out(OutputStream out) {
        this.out = out;
        return this;
    }

    /**
     * 指定输出文件
     *
     * @param outFile
     * @return
     */
    public JxlsBuilder out(File outFile) {
        this.outFile = outFile;
        return this;
    }

    /**
     * 指定输出文件绝对路径
     *
     * @param outPath
     * @return
     */
    public JxlsBuilder out(String outPath) {
        this.outFile = new File(outPath);
        return this;
    }

    /**
     * 添加数据
     *
     * @param name
     * @param value
     * @return
     */
    public JxlsBuilder putVar(String name, Object value) {
        context.putVar(name, value);
        return this;
    }

    /**
     * 添加数据
     *
     * @param map
     * @return
     */
    public JxlsBuilder putAll(Map map) {
        for (String key : map.keySet()) {
            putVar(key, map.get(key));
        }
        return this;
    }

    /**
     * 删除数据
     *
     * @param name
     * @return
     */
    public JxlsBuilder removeVar(String name) {
        context.removeVar(name);
        return this;
    }

    /**
     * 获取数据
     *
     * @param name
     * @return
     */
    public Object getVar(String name) {
        return context.getVar(name);
    }

    /**
     * 添加自定义工具对象
     *
     * @param name
     * @param function
     * @return
     */
    public JxlsBuilder addFunction(String name, Object function) {
        funcs.put(name, function);
        return this;
    }

    /**
     * 设置图片根路径
     *
     * @param root
     * @return
     */
    public JxlsBuilder imageRoot(String root) {
        this.imageRoot = root;
        return this;
    }

    /**
     * 设置是否忽略图片错误
* true 忽略图片错误,如果图片读取失败时不终止运行,继续生成excel * false 默认,不忽略图片错误,如果图片读取失败终止生成excel * * @param ignoreImageMiss */ public JxlsBuilder ignoreImageMiss(boolean ignoreImageMiss) { this.ignoreImageMiss = ignoreImageMiss; return this; } public File getInFile() { return inFile; } public File getOutFile() { return outFile; } public static void main(String[] args) throws Exception { JxlsBuilder.getBuilder("xx.xlsx") .out("D:/xx.xlsx") .putVar("", null) .build(); } /** * 生成excel后删除指定表格 * * @param sheetNames * @return */ public JxlsBuilder removeSheet(String... sheetNames) { this.removeSheetNames = sheetNames; return this; } }

如果生成的excel报表有图片可添加excel图片处理类(可不添加)

public class JxlsImage {
    public static final String IMAGE_SIZE_TYPE_AUTO = "auto";
    public static final String IMAGE_SIZE_TYPE_ORIGINAL = "original";
    private byte[] pictureData;
    private String pictureType;

    public byte[] getPictureData() {
        return pictureData;
    }

    public void setPictureData(byte[] pictureData) {
        this.pictureData = pictureData;
    }

    public String getPictureType() {
        return pictureType;
    }

    public void setPictureType(String pictureType) {
        this.pictureType = pictureType;
    }

    public int getWorkbookImageType() {
        switch (pictureType.toUpperCase()) {
            case "PNG":
                return Workbook.PICTURE_TYPE_PNG;
            case "EMF":
                return Workbook.PICTURE_TYPE_EMF;
            case "WMF":
                return Workbook.PICTURE_TYPE_WMF;
            case "PICT":
                return Workbook.PICTURE_TYPE_PICT;
            case "DIB":
                return Workbook.PICTURE_TYPE_DIB;
            default:
                return Workbook.PICTURE_TYPE_JPEG;
        }
    }

    public ImageType getJxlsImageType() {
        if ("jpg" .equalsIgnoreCase(pictureType)) {
            return ImageType.JPEG;
        }
        return ImageType.valueOf(pictureType);
    }
}

3.1.2 对excel文件格式规范,操作等辅助类
对行操作的规范配置

public class GridCommand extends org.jxls.command.GridCommand {

    @Override
    public Size applyAt(CellRef cellRef, Context context) {
        String props = getProps();
        if(!StringUtils.contains(props, ",")){
            Object value = getTransformationConfig().getExpressionEvaluator().evaluate(props, context.toMap());
            if(value instanceof String){
                props = (String) value;
            } else if (value instanceof String[]){
                props = StringUtils.join((String[]) value, ",");
            } else {
                throw new IllegalArgumentException("props 属性只支持 String 和 String[]");
            }
            setProps(props);
        }
        return super.applyAt(cellRef, context);
    }
}

保持单元格样式配置

public class KeepCommand extends AbstractCommand {

    private Area area;

    public KeepCommand() {
    }

    @Override
    public Command addArea(Area area) {
        if( super.getAreaList().size() >= 1){
            throw new IllegalArgumentException("You can add only a single area to 'keep' command");
        }
        this.area = area;
        return super.addArea(area);
    }

    @Override
    public String getName() {
        return "keep";
    }

    @Override
    public Size applyAt(CellRef cellRef, Context context) {
        if( area == null ){
            throw new IllegalArgumentException("No area is defined for keep command");
        }
        //恢复原有的样式
        area.applyAt(cellRef, context);
        return area.getSize();
    }
}

合并单元格配置

/**
 * 

合并单元格

* jx:merge( * lastCell="单元格" * [, cols="合并的列数"] * [, rows="合并的行数"] * [, minCols="最小合并的列数"] * [, minRows="最小合并的行数"] * ) */ public class MergeCommand extends AbstractCommand{ private String cols; //合并的列数 private String rows; //合并的行数 private String minCols; //最小合并的列数 private String minRows; //最小合并的行数 private CellStyle cellStyle;//第一个单元格的样式 private Area area; @Override public String getName() { return "merge"; } @Override public Command addArea(Area area) { if (super.getAreaList().size() >= 1) { throw new IllegalArgumentException("You can add only a single area to 'merge' command"); } this.area = area; return super.addArea(area); } @Override public Size applyAt(CellRef cellRef, Context context) { int rows = getVal(this.rows, context); int cols = getVal(this.cols, context); rows = Math.max(getVal(this.minRows, context), rows); cols = Math.max(getVal(this.minCols, context), cols); rows = rows > 0 ? rows : area.getSize().getHeight(); cols = cols > 0 ? cols : area.getSize().getWidth(); if(rows > 1 || cols > 1){ Transformer transformer = this.getTransformer(); if(transformer instanceof PoiTransformer){ poiMerge(cellRef, context, (PoiTransformer)transformer, rows, cols); }else if(transformer instanceof JexcelTransformer){ jexcelMerge(cellRef, context, (JexcelTransformer)transformer, rows, cols); } } area.applyAt(cellRef, context); return new Size(cols, rows); } protected Size poiMerge(CellRef cellRef, Context context, PoiTransformer transformer, int rows, int cols){ Sheet sheet = transformer.getWorkbook().getSheet(cellRef.getSheetName()); CellRangeAddress region = new CellRangeAddress( cellRef.getRow(), cellRef.getRow() + rows - 1, cellRef.getCol(), cellRef.getCol() + cols - 1); sheet.addMergedRegion(region); //合并之后单元格样式会丢失,以下操作将合并后的单元格恢复成合并前第一个单元格的样式 area.applyAt(cellRef, context); if(cellStyle == null){ PoiCellData cellData = (PoiCellData)transformer.getCellData(area.getStartCellRef()); if(cellData != null){ cellStyle = cellData.getCellStyle(); } } setRegionStyle(cellStyle, region, sheet); return new Size(cols, rows); } protected Size jexcelMerge(CellRef cellRef, Context context, JexcelTransformer transformer, int rows, int cols){ try { transformer.getWritableWorkbook().getSheet(cellRef.getSheetName()) .mergeCells( cellRef.getRow(), cellRef.getCol(), cellRef.getRow() + rows - 1 , cellRef.getCol() + cols - 1); area.applyAt(cellRef, context); } catch (WriteException e) { throw new IllegalArgumentException("合并单元格失败"); } return new Size(cols, rows); } private static void setRegionStyle(CellStyle cs, CellRangeAddress region, Sheet sheet) { for (int i = region.getFirstRow(); i <= region.getLastRow(); i++) { Row row = sheet.getRow(i); if (row == null) { row = sheet.createRow(i); }for (int j = region.getFirstColumn(); j <= region.getLastColumn(); j++) { Cell cell = row.getCell(j); if (cell == null) { cell = row.createCell(j); } if (cs == null){ cell.getCellStyle().setAlignment(CellStyle.ALIGN_CENTER); cell.getCellStyle().setVerticalAlignment(CellStyle.VERTICAL_CENTER); }else { cell.setCellStyle(cs); } } } } private int getVal(String expression, Context context){ if(JxlsUtil.me().hasText(expression)){ Object obj = getTransformationConfig().getExpressionEvaluator().evaluate(expression, context.toMap()); try { return Integer.parseInt(obj.toString()); } catch (NumberFormatException e) { throw new IllegalArgumentException("表达式:" + expression + " 解析失败"); } } return 0; } public String getCols() { return cols; } public void setCols(String cols) { this.cols = cols; } public String getRows() { return rows; } public void setRows(String rows) { this.rows = rows; } public String getMinCols() { return minCols; } public void setMinCols(String minCols) { this.minCols = minCols; } public String getMinRows() { return minRows; } public void setMinRows(String minRows) { this.minRows = minRows; } }

插入图片配置

/**
 * 

插入图片

* jx:image( * src="byte[] | JxlsImage | 图片路径(相对图片目录或绝对绝对路径)", * lastCell="图片右下角单元格坐标,左上角坐为指令所在单元格" * [,imageType="JPG"] * [,size="auto | original"] * [,scaleX="1"] * [,scaleY="1"] * ) */ public class ImageCommand extends AbstractCommand { private byte[] imageBytes; private ImageType imageType = ImageType.PNG; private Area area; /** * 图片源,可以byte[]、JxlsImage对象和图片路径 */ private String src; /** * 插入图片大小,poi4.0以上适用 * @see Picture.resize(scaleX,scaleY) */ private String scaleX; private String scaleY; /** * 自适应大小类型
* auto 默认,自适应单元格大小
* original 图片原大小 */ private String size; public ImageCommand() { } public ImageCommand(String image, ImageType imageType) { this.src = image; this.imageType = imageType; } public ImageCommand(byte[] imageBytes, ImageType imageType) { this.imageBytes = imageBytes; this.imageType = imageType; } @Override public Command addArea(Area area) { if( super.getAreaList().size() >= 1){ throw new IllegalArgumentException("You can add only a single area to 'image' command"); } this.area = area; return super.addArea(area); } @Override public String getName() { return "image"; } @Override public Size applyAt(CellRef cellRef, Context context) { if( area == null ){ throw new IllegalArgumentException("No area is defined for image command"); } Transformer transformer = getTransformer(); Size size = area.getSize(); try { JxlsImage img = getImage(context); if(img != null){ if(transformer instanceof PoiTransformer){ addImage(cellRef, context, (PoiTransformer) transformer, img); }else{ //获取图片显示区域是时候,多加一行和一列,获取完之后再恢复原来大小 size.setWidth(size.getWidth() + 1); size.setHeight(size.getHeight() + 1); AreaRef areaRef = new AreaRef(cellRef, size); size.setWidth(size.getWidth() - 1); size.setHeight(size.getHeight() - 1); transformer.addImage(areaRef, img.getPictureData(), img.getJxlsImageType()); } } } catch (Exception e) { Boolean ignoreImageMiss = (Boolean) context.getVar("_ignoreImageMiss"); //是否忽略图片读取失败,并继续生成excel后面操作,否则终止生成 if(ignoreImageMiss == null || !ignoreImageMiss){ throw new IllegalArgumentException("出现异常,终止生成excel", e); } } //恢复原有的样式 area.applyAt(cellRef, context); return size; } private void addImage(CellRef cellRef, Context context, PoiTransformer transformer, JxlsImage img){ Workbook wb = transformer.getWorkbook(); int pictureIdx = wb.addPicture(img.getPictureData(), img.getWorkbookImageType()); Sheet sheet = wb.getSheet(cellRef.getSheetName()); Drawing drawing = sheet.createDrawingPatriarch(); CreationHelper helper = wb.getCreationHelper(); ClientAnchor anchor = helper.createClientAnchor(); anchor.setCol1(cellRef.getCol()); anchor.setCol2(cellRef.getCol() + area.getSize().getWidth()); anchor.setRow1(cellRef.getRow()); anchor.setRow2(cellRef.getRow() + area.getSize().getHeight()); Picture pict = drawing.createPicture(anchor, pictureIdx); if(JxlsUtil.me().hasText(scaleX) || JxlsUtil.me().hasText(scaleY)){ // double scale_x = 1d, scale_y = 1d; // if(JxlsUtil.me().hasText(scaleX)){ // Object scaleXObj = getTransformationConfig().getExpressionEvaluator().evaluate(scaleX, context.toMap()); // scale_x = Double.valueOf(scaleXObj.toString()); // } // if(JxlsUtil.me().hasText(scaleY)){ // Object scaleXObj = getTransformationConfig().getExpressionEvaluator().evaluate(scaleY, context.toMap()); // scale_y = Double.valueOf(scaleXObj.toString()); // } // pict.resize(scale_x, scale_y); }else if(JxlsImage.IMAGE_SIZE_TYPE_ORIGINAL.equalsIgnoreCase(size)){ pict.resize(); }else{ pict.resize(1d); } } private JxlsImage getImage(Context context) throws IOException { if(imageBytes == null && src != null){ Object imgObj = getTransformationConfig().getExpressionEvaluator().evaluate(src, context.toMap()); if(imgObj != null){ if(imgObj instanceof byte[]) { imageBytes = (byte[]) imgObj; }else if(imgObj instanceof JxlsImage) { return (JxlsImage) imgObj; }else if(imgObj instanceof String){ String imgSrc = (String) imgObj; String imageRoot = (String)context.getVar("_imageRoot"); //判断是相对路径还是绝对路径 if (!JxlsUtil.me().isAbsolutePath(imgSrc)) { if(imageRoot.startsWith("classpath:")){ //文件在jar包内 String templateRoot = imageRoot.replaceFirst("classpath:", ""); InputStream resourceAsStream = JxlsBuilder.class.getResourceAsStream(templateRoot + File.separator + imgSrc); return JxlsUtil.me().getJxlsImage(resourceAsStream, imgSrc); }else{ //相对路径就从模板目录获取文件 return JxlsUtil.me().getJxlsImage(imageRoot + File.separator + imgSrc); } } else { //绝对路径 return JxlsUtil.me().getJxlsImage(imgSrc); } } } } if(imageBytes != null){ JxlsImage img = new JxlsImage(); img.setPictureData(imageBytes); if(imageType != null){ img.setPictureType(imageType.toString()); }else{ img.setPictureType("jpg"); } return img; } throw new IllegalArgumentException("图片读取失败 " + JxlsUtil.me().getNotNull(src, "")); } public String getSrc() { return src; } public void setSrc(String src) { this.src = src; } public void setImageType(String strType){ imageType = ImageType.valueOf(strType); } public String getScaleX() { return scaleX; } public void setScaleX(String scaleX) { this.scaleX = scaleX; } public String getScaleY() { return scaleY; } public void setScaleY(String scaleY) { this.scaleY = scaleY; } public String getSize() { return size; } public void setSize(String size) { this.size = size; } }

3.2 使用jxls生成excel报表并导出
3.2.1 写导出报表接口

public Object exportCourseList(List courseIds) throws Exception {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        HttpHeaders httpHeaders = new HttpHeaders();
        List courseBases=new ArrayList<>();
        if (CollectionUtils.isNotEmpty(courseIds)){
            List baseInfos = this.getByCourseIds(courseIds);
            courseBases = baseInfos.stream().map(x->{
                DmtCourseBaseinfoDto.ExportCourseBase dto =new DmtCourseBaseinfoDto.ExportCourseBase();
                BeanUtils.copyProperties(x,dto);
                dto.setStatusName(CourseStatus.getNameByCode(x.getStatus()));
                return dto;
            }).collect(Collectors.toList());
        }

        //获取excel模板
        ClassPathResource classPathResource = new ClassPathResource("excel/courseList.xlsx");
        File template =classPathResource.getFile();
        JxlsBuilder.getBuilder(template)
                .out(os)
                .putVar("list", courseBases)
                .build();
        httpHeaders.add("Content-Disposition", "attachment;filename=" + new String(("课程列表信息" + IdWorker.getIdStr() +
                ".xlsx"
                //获取excel模板
        ).getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
        httpHeaders.add("Content-Length", String.valueOf(os.size()));
        httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        return new ResponseEntity<>(os.toByteArray(), httpHeaders, HttpStatus.OK);
    }

3.2.2 excel报表模板创建
在这里插入图片描述
创建注意事项:
(1)在A1单元格添加批注(定义区域,需包含所有涉及的单元格)
在这里插入图片描述

(2)在需要循环数据的第一行第一列添加批注,如模板所示,我们需要在第二行循环数据填充,那么我们需要在A2单元格添加下列批注(items为循环的集合名称,var为集合别名,lastCell为当前循环的生效区域)
JXLS (excel报表生成/导出工具)的配置与使用_第1张图片

(3)序号可直接使用=ROW(A2)-1来设置
(4)部分单元格如果需要设置格式,可现在模板中直接设置,如需要设置日期格式,可直接在对应单元格设置单元格格式为日期
(5)模板中列表的字段名需要与代码的字段名匹配,并且模板的字段名需要使用对应的格式 如${c.courseName}

测试成功示例
在这里插入图片描述

你可能感兴趣的:(java,maven,spring)