Maison >Les sujets >excel >Utilisez EasyPOI pour exporter avec élégance les données du modèle Excel (y compris les images)
Avant-propos
Récemment, un lecteur posait des questions sur easypoi, j'ai donc pris le temps de rédiger un article.
Texte
La fonction d'EasyPOI est tout comme le nom Easy. La fonction principale est la facilité, afin qu'une personne qui n'a jamais été exposée à POI puisse facilement écrire une exportation Excel, une exportation de modèle Excel, une importation Excel et Word. exportation de modèles. Grâce à des annotations simples et à un langage de modèle (syntaxe d'expression familière), des méthodes d'écriture auparavant complexes peuvent être complétées.
Cet article utilise principalement une analyse simple pour permettre aux lecteurs de savoir comment rédiger des modèles Excel et comment utiliser EasyPOI pour exporter des données Excel qui répondent à leurs besoins, simplifiant ainsi le codage. Parallèlement, cet article expliquera également certaines fonctions peu courantes comme la fonction d'exportation d'images, afin que les lecteurs puissent éviter les pièges.
EasyPOI4.0.0 et les versions ultérieures dépendent d'Apache POI 4.0.0 et des versions ultérieures. Par conséquent, dans la configuration maven, les numéros de version des deux doivent correspondre.
Il convient de noter qu'Apache POI 4.0.0 présente des changements importants par rapport à la version précédente. Si la partie opération Excel du code précédent dépend de l'ancienne version, il n'est pas recommandé d'utiliser la version 4.0.0 et les versions ultérieures. Bien entendu, si le code précédent n’implique pas ou implique rarement les détails de création de WorkBook, l’utilisation de la nouvelle version ne pose aucun problème.
Le projet que l'auteur doit réécrire est basé sur JEECG version 3.7 et s'appuie sur la version 3.9 d'Apache POI. La version la plus élevée de jeasypoi maintenue par JEECG n'est que la 2.2.0, et cette version ne prend pas en charge la fonction d'exportation d'image de modèle. En parlant de ça, je veux me plaindre de l'équipe JEECG suivante. Puisque je n'ai pas l'intention de maintenir jeasypoi, pourquoi ne pas simplement utiliser l'EasyPOI officiel directement dans le projet. Combien de fosses la version 2.2.0 de jeasypoi a-t-elle creusées pour les développeurs ? ?
Afin d'être compatible avec l'ancienne version et de vouloir utiliser la fonction d'export d'images apportée par EasyPOI, la version EasyPOI que j'ai finalement adoptée est la 3.3.0, et la dépendance Apache POI correspondante est la 3.15.
La configuration de Maven est la suivante :
<properties> <poi.version>3.15</poi.version> <easypoi.version>3.3.0</easypoi.version> </properties> <dependencies> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>${poi.version}</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>${poi.version}</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>${poi.version}</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> <version>${poi.version}</version> </dependency> <dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-web</artifactId> <version>${easypoi.version}</version> </dependency> </dependencies>
Nous utilisons la fonction d'exportation de modèle d'EasyPOI car nous ne voulons pas concevoir le style du rapport Excel via le codage, donc le premier L'étape du travail consiste à concevoir le modèle Excel et à distinguer clairement quelles parties sont fixes et quelles parties doivent être remplies en boucle. EasyPOI possède son propre langage d'expression. Pour une introduction détaillée de chaque expression, veuillez vous référer au lien de référence ci-dessous.
Certains modèles simples ne seront pas expliqués en détail ici, seuls les rendus et le contenu de configuration du modèle seront affichés. Lorsque les lecteurs comprendront comment créer des modèles complexes et remplir des valeurs, les plus simples seront rapidement compris.
Premier coup d'œil aux rendus du rapport :
Ensuite, regardez le modèle lui-même :
Après avoir regardé les deux images ci-dessus, avez-vous déjà ressenti la puissance de la fonction d'exportation de modèles ?
Le modèle à présenter ci-dessous est relativement complexe, contrairement à la situation courante où une ligne est un enregistrement, donc la configuration du modèle sera présentée en détail, et par la manière Une brève introduction à quelques expressions d'EasyPOI.
Regardons d'abord les rendus :
Ensuite, regardons le modèle :
En comparant ces deux images, avez-vous l'impression que la connaissance peut changer votre destin ?
À partir des images du modèle et des rendus des informations sur le produit, nous avons constaté que l'ensemble du modèle est en fait divisé en parties supérieure et inférieure. La partie supérieure correspond aux informations d'en-tête inchangées et la partie inférieure correspond aux informations détaillées sur le produit insérées de manière cyclique. Nous nous concentrons donc sur la grammaire dans la seconde moitié.
La première colonne dans la moitié inférieure de l'image n'est pas affichée complètement, il s'agit en fait de {{!fe: list t.id.
Remarque, il n'y a pas de symbole }} ici ! Selon la documentation officielle d'EasyPOI, {{}} représente une expression et la valeur à l'intérieur est obtenue en fonction de l'expression. Si vous regardez attentivement l'image, vous constaterez que le symbole de clôture {{}} de l'expression apparaît dans le coin inférieur droit de l'image. C'est-à-dire qu'à partir de la première colonne {{ et se terminant dans le coin inférieur droit}}, tout le reste fait partie de l'expression.
Étant donné que toutes les informations du modèle font partie de l'expression, même les chaînes ordinaires doivent être spécialement marquées. Les sous-expressions de l'expression sont expliquées une par une ci-dessous.
!fe : Parcourez les données sans créer de lignes.
Cette phrase du document officiel peut être un peu déroutante à comprendre pour tout le monde. Que signifie ne pas créer de dispute ? En fait, ne pas créer de ligne est relatif à la création d'une ligne, et l'expression pour créer une ligne est fe :.
Tout comme chaque enregistrement de la base de données correspond à un objet entité, créer une ligne signifie que chaque ligne est un objet entité. Les attributs de cet objet entité sont encapsulés avec des expressions {{}}.
Ne pas créer de ligne signifie qu'il n'y a qu'un seul objet entité Objet dans l'expression entière, mais cet objet est spécial. Il est assemblé par N entités dans la liste. Chaque entité fait non seulement référence au modèle lui-même, mais inclut également le style Excel, comme le nombre de cellules qu'elle occupe, les coordonnées des cellules, l'ordre de disposition, etc.
list est un nom personnalisé qui représente la collection de données dans l'expression. Le code utilise list comme clé pour obtenir la collection de valeursà partir de Map994a833a6ffa28d85b72cb15422c29d6.
La liste de noms est facile à comprendre. Il ne s'agit que d'un espace réservé et peut être choisi avec désinvolture. Lorsque EasyPOI analyse la liste, il saura qu'il existe un ensemble de valeurs de la clé dans Map994a833a6ffa28d85b72cb15422c29d6. Lorsqu'il analysera les données plus tard, il pourra simplement les extraire de l'ensemble.
Recherchez sur le compte officiel Java Zhiyin, répondez « Backend Interview » et nous vous donnerons un guide de questions d'entretien Java.pdf
t valeur prédéfinie, représentant n'importe quel objet de la collection.
Nous pouvons à peu près sentir à partir du modèle que chaque objet de la liste est appelé t, et t.name représente l'attribut name de t, donc le nom t peut être appelé avec désinvolture. Quoi qu'il en soit, c'est la même chose que list, et. il fonctionne comme un espace réservé.
Mais en réalité, c'est un grand gouffre ! Si vous remplacez t par une autre valeur telle que g, écrivez g.name g.code, etc. ailleurs dans le modèle, il ne sera finalement pas analysé ! La documentation officielle n’insiste pas sur ce point, mais l’auteur ne l’a découvert qu’après avoir marché sur le piège !
]] Caractère de nouvelle ligne Exportation traversante multiligne.
L'explication officielle de ce symbole est également déroutante. Qu'est-ce qu'un caractère de nouvelle ligne et une exportation de parcours multiligne ? En fait, cela signifie que lorsque l'expression contient ce symbole, le contenu après la ligne ne sera pas analysé, qu'il y ait ou non un autre contenu ou un autre style derrière.
Ce symbole doit être écrit dans la dernière colonne de chaque ligne, sinon le nombre de lignes et de colonnes sera différent et une exception de pointeur nul sera signalée lorsque EasyPOI effectuera une affectation interne.
'' Un guillemet simple représente une valeur constante '' Par exemple, « 1 », alors le résultat est 1
L'introduction ici dans le document officiel comporte également des pièges. '' signifie valeur constante, mais en fait, c'est une erreur de l'avoir uniquement dans Excel, car lorsque Excel rencontre ' dans une cellule, il pensera que ce qui suit sont toutes des chaînes, vous devez donc écrire '' type de bibliothèque : ' dans la cellule. , de sorte que ce qui est affiché est « Type de bibliothèque : », et non le type de bibliothèque de chaînes : ».
Après l'analyse ci-dessus, le modèle dans l'image est en fait similaire au suivant :
{{!fe: list t.id ‘库别:’ t.bin 换行 ‘商品名称:’ t.name 换行 ‘商品编号:’ t.code t.barcode 换行 ‘生产日期:’ t.proDate 换行 ‘进货日期:’ t.recvDate}}
如果list中有多条记录,上述字符串就再循环拼接一些内容,最终都在一个{{}}表达式中。
至此,模板的设计已剖析完毕,读者可根据自己的需求结合官方文档自行设计模板。下面将对模板赋值进行介绍。
从上节的描述中可知,只需要准备一个Map994a833a6ffa28d85b72cb15422c29d6的对象即可,其中键为list,值为一个List数组,数组中元素类型为Map994a833a6ffa28d85b72cb15422c29d6。代码如下:
Map<String, Object> total = new HashMap<>(); List<Map<String, Object>> mapList = new ArrayList<>(); for (int i = 1; i <= 5; i++) { Map<String, Object> map = new HashMap<>(); map.put("id", i + ""); map.put("bin", "001 1000千克"); map.put("name", "商品" + i); map.put("code", "goods" + i); map.put("proDate", "2019-05-30"); map.put("recvDate", "2019-07-07"); // 插入图片 ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(); BufferedImage bufferImg = ImageIO.read(BarcodeUtil.generateToStream("001")); ImageIO.write(bufferImg, "jpg", byteArrayOut); ImageEntity imageEntity = new ImageEntity(byteArrayOut.toByteArray(), 200, 1000); map.put("barcode", imageEntity); mapList.add(map); } total.put("list", mapList);
上述代码中需要特殊关注的是图片导出部分。EasyPOI导出图片有两种方式,一种是通过图片的Url,还有一种是获取图片的byte[]
,毕竟图片的本质就是byte[]
。因为笔者的项目中图片不是存放在数据库之中,而是需要根据查询结果动态生成条码,所以通过byte[]
导出图片。
ImageEntity是EasyPOI内置的一个JavaBean,用于设定图片的宽度和高度、导出方式、RowSpan和ColumnSpan等。调试EasyPOI的源码可知,当设置了RowSpan或者ColumnSpan之后,图片的高度设置就失效了,图片大小会自动填充图片所在的单元格。
图片导出的坑点在于导出图片的大小。假设我们将四个单元格合成为一个,希望导出的图片能填充合并之后的单元格,但是对不起,EasyPOI暂时做不到,它只会填充合并之前左上角的单元格,具体原因如下源码所示:
//BaseExportService.java ClientAnchor anchor; if (type.equals(ExcelType.HSSF)) { anchor = new HSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1); } else { anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1); }
可以看到,在创建图片插入位置的时候已经指定了图片的跨度为1行1列,即左上角的单元格。如果之前又设置了RowSpan或者ColumnSpan,那么图片高度的设置也会失效,最终导致导出的图片非常小。
搜索Java知音公众号,回复“后端面试”,送你一份Java面试题宝典.pdf
个人认为ImageEntity提供的RowSpan或者ColumnSpan的set方法并没有什么用,因为我们动态创建的合并单元格并不能被赋值。所以,导出图片的最好方式就是直接指定它的高度,因为宽度会自动填充单元格,模板中单元格的宽度要合适。
//ExcelExportOfTemplateUtil.java if (img.getRowspan()>1 || img.getColspan() > 1){ img.setHeight(0); PoiMergeCellUtil.addMergedRegion(cell.getSheet(),cell.getRowIndex(), cell.getRowIndex() + img.getRowspan() - 1, cell.getColumnIndex(), cell.getColumnIndex() + img.getColspan() -1); }
以上准备工作全部完成后就可以将模板和数据进行组装了,或者说是渲染,代码如下所示:
public static void exportByTemplate(String templateName, Map<String, Object> data, OutputStream fileOut) { TemplateExportParams params = new TemplateExportParams("export/template/" + templateName, true); try { Workbook workbook = ExcelExportUtil.exportExcel(params, data); workbook.write(fileOut); } catch (Exception e) { LogUtil.error("", e); } }
网上针对EasyPOI的介绍多限于最基本的行插入功能,但实际上Excel模板的需求可能各式各样。本文只是抛砖引玉,对EasyPOI中的部分概念做了详细介绍,希望帮助大家少踩坑。
如果想详细了解EasyPOI的各种功能,参考链接中的文档说明及测试项目源码就是最好的学习资料。希望大家都能得心应手地使用EasyPOI,大大提升开发效率!
EasyPOI官方文档
EasyPOI测试项目
近日有网友求助我解决EasyPOI的复杂模板配置问题,通过解决该网友的问题发现了EasyPOI中的几个坑点,补充说明几个问题。
Comment configurer des modèles complexes pris en charge par EasyPOI a été décrit dans la section Analyse de la conception de modèles complexes. La configuration de ce modèle est tout à fait correcte, mais il y a trois points qui ne sont pas clairement énoncés, et il est facile pour tout le monde de se tromper en copiant la gourde :
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!