I. Introduction▲
Suite à la lecture des tutoriels intitulés « Les fichiers CSV avec Java » et « Charger des données depuis un fichier CSV simple en 5 minutes », qui décrivent différentes façons de lire des fichiers au format CSV, vous avez été nombreux à me demander comment effectuer la même chose sur des fichiers Excel. Étant donnée la structure tabulaire des fichiers CSV et d'Excel, au moins dans sa représentation, il est en effet légitime de se poser la question. Ce document va donc tenter d'y répondre.
Pour cela, nous allons utiliser la bibliothèque Apache POI qui va faire l'essentiel du travail, notamment en décryptant le format Excel.
I-A. Avant de commencer▲
Pour écrire ce tutoriel, j'ai utilisé les éléments suivants :
- Java JDK 1.7.0_51 ;
- Eclipse Luna 4.4 ;
- Maven 3.0.5 ;
- JUnit 4.11 ;
- Log4j 1.2.17 ;
- POI 3.10.
I-B. Mise à jour▲
28/08/2014 : création du document
25/09/2014 : ajout d'un paragraphe sur l'évaluation des formules
II. Découverte du projet d'exemple▲
II-A. Télécharger, installer et importer le projet d'exemple▲
Durée estimée : 1 minute.
Pour commencer, je vous propose de télécharger le fichier Zip « article-poi-5-min-01.zip », contenant un projet Java-Maven d'exemple.
Compilez le projet d'exemple et importez-le dans Eclipse (comme expliqué dans le tutoriel « Importer un projet Maven dans Eclipse en 5 minutes »).
Pour suivre ce tutoriel, vous pouvez vous contenter de lire les codes proposés ci-dessous (codes complets en annexe).
II-B. Les données à lire▲
Ce tutoriel montre comment lire le fichier Excel 2010, nommé « chien-01.xlsx », que vous trouverez dans le dossier « src/test/resources ». Il contient une liste de chiens avec quelques attributs comme leurs noms, tailles, races, etc.
II-C. Les objets du modèle▲
Durée estimée : 30 secondes.
Comme la plupart de mes articles d'exemple parlent de chien, j'ai repris les objets du domaine que j'utilise habituellement. L'objet central est sans surprise l'interface « Chien » :
public interface Chien extends Serializable {
String getNom();
String getNomComplet();
Sexe getSexe();
RaceDeChien getRace();
List<String> getCouleurs();
Double getPoids();
}En complément, je vous propose une implémentation « SimpleChien » qui n'a rien de particulier :
public class SimpleChien implements Chien {
private String nom;
private String nomComplet;
private Sexe sexe;
private RaceDeChien race;
private List<String> couleurs;
private Double poids;
...Les codes sources complets sont proposés en annexe.
Quant aux enum « Sexe » et « RaceDeChien », elles ne devraient pas nécessiter trop de questions :
public enum Sexe {
FEMALE(2), //
MALE(1);
private final int code;
...
}public enum RaceDeChien {
BASSET_ALPES("Basset des Alpes", "basset_alp"), //
BERGER_ALLEMAND("Berger allemand", "berger_all"), //
CANICHE("Caniche", "caniche"), //
HARRIER("Harrier", "harrier"), //
GOLDEN("Golden retriever", "golden_ret"), //
ROTTWEILER("Rottweiler", "rottweiler"), //
WESTIE("Westie", "westie");
private final String label;
private final String code;
...
}Nous allons lire des données sur des chiens. Cela va se faire dans une classe de type DAO dont l'interface « ChienDao » (simplement reprise d'un autre tutoriel) définit le contrat :
public interface ChienDao {
List<Chien> findAllChiens();
}Dans ce projet d'exemple, je ne vous pollue pas avec les différentes implémentations (cf. mes autres articles) pour lire les données depuis un fichier CSV, une base de données, un web service, etc. Je vous propose simplement l'implémentation « PoiChienDao » qui est vide pour l'instant :
public class PoiChienDao implements ChienDao {
@Override
public List<Chien> findAllChiens() {
throw new UnsupportedOperationException("not yet");
}
}Avec tout cela, on a de quoi avancer tranquillement.
III. Action▲
III-A. Écriture des tests▲
Durée estimée : 1 minute.
Avant d'aller plus loin, nous allons écrire des tests unitaires. En gros nous allons faire du « TDD » (Test Driven Development) ou plus précisément du « 3T »(Tests en Trois Temps). Ceci sera fait dans la classe de test « PoiChienDaoTest », dont une version vide est déjà présente dans le projet d'exemple. Dans cet article, on ne va pas non plus chercher à être absolument exhaustif.
L'interface ChienDao ne fait que renvoyer la liste des chiens. On va donc se limiter à ça :
public class PoiChienDaoTest {
private static final String fileName = "src/test/resources/chien-01.xlsx";
private ChienDao dao;
@Before
public void doBefore() {
dao = new PoiChienDao(fileName);
}
@Test
public void testFindAllchien() {
// Arrange
final int expectedSize = 5;
// Act
List<Chien> chiens = dao.findAllChiens();
// Assert
Assert.assertNotNull(chiens);
Assert.assertEquals(expectedSize, chiens.size());
}
...Notez que j'ai ajouté un constructeur au DAO pour que ça compile :
public class PoiChienDao implements ChienDao {
private String fileName;
public PoiChienDao(final String fileName) {
super();
this.fileName = fileName;
}
...On peut aussi tester les noms, les tailles, les races, etc.
public class PoiChienDaoTest {
...
@Test
public void testOrdreDesChiens() {
log.debug("testFindAllchien");
// Arrange
final String[] expectedNoms = { "Milou", "Pluto", "Lassie", "Volt", "Medor" };
// Act
final List<Chien> chiens = dao.findAllChiens();
// Assert
for (int i = 0; i < expectedNoms.length; i++) {
Assert.assertEquals(expectedNoms[i], chiens.get(i).getNom());
}
}
@Test
public void testTaillesDesChiens() {
log.debug("testFindAllchien");
// Arrange
final double[] expectedPoids = { 12.5, 24, 32.3, 14, 32 };
// Act
final List<Chien> chiens = dao.findAllChiens();
// Assert
for (int i = 0; i < expectedPoids.length; i++) {
Assert.assertEquals(expectedPoids[i], chiens.get(i).getPoids().doubleValue(), 0.001d);
}
}
@Test
public void testRacesDesChiens() {
log.debug("testFindAllchien");
// Arrange
final RaceDeChien[] expectedRaces = { CANICHE, GOLDEN, BERGER_ALLEMAND, CANICHE, ROTTWEILER };
// Act
final List<Chien> chiens = dao.findAllChiens();
// Assert
for (int i = 0; i < expectedRaces.length; i++) {
Assert.assertEquals(expectedRaces[i], chiens.get(i).getRace());
}
}Quand on lance les tests, on constate qu'ils sont tous rouges, ce qui est justement ce qu'on voulait. On peut maintenant passer à la suite.
III-B. Ajout d'Apache POI▲
Durée estimée : 30 secondes.
Pour profiter de la bibliothèque « Apache POI », vous devez ajouter des dépendances dans le fichier « pom.xml » :
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.10-FINAL</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.10-FINAL</version>
</dependency>Relancez ensuite une installation Maven, en sautant les tests :
mvn clean install eclipse:eclipse -Dmaven.test.skip
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Chiens 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
...
Downloading: http://.../public/org/apache/poi/poi-ooxml-schemas/3.10-FINAL/poi-ooxml-schemas-3.10-FINAL.jar
Downloaded: http://.../public/org/apache/poi/poi-ooxml-schemas/3.10-FINAL/poi-ooxml-schemas-3.10-FINAL.jar (4831 KB at 1223.0 KB/sec)
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.273s
[INFO] Finished at: Mon Aug 04 20:27:59 GMT+01:00 2014
[INFO] Final Memory: 12M/157M
[INFO] ------------------------------------------------------------------------N'oubliez pas de faire un « refresh » (touche F5) dans Eclipse. Vous devriez constater que la bibliothèque « poi-3.10-Final.jar » est apparue dans le dossier « referenced Librairies ».
III-C. Lecture du fichier Excel 2010▲
Durée estimée : 3 minutes.
Pour commencer, il faut ouvrir le fichier. Pour la version 2010 d'Excel, cela se fait à l'aide de l'utilitaire « WorkbookFactory » :
@Override
public List<Chien> findAllChiens() {
final File file = new File(fileName);
try {
final Workbook workbook = WorkbookFactory.create(file);
} catch (InvalidFormatException | IOException e) {
e.printStackTrace();
}
...
}Un fichier Excel est constitué de plusieurs feuilles qu'on peut sélectionner soit par leur nom, soit par leur position. Dans le fichier d'exemple, la feuille qui nous intéresse se nomme « Feuil1 » :
final Workbook workbook = WorkbookFactory.create(file);
final Sheet sheet = workbook.getSheet("Feuil1");Personnellement, je préfère utiliser le nom, plutôt que la position. En effet, on n'est pas à l'abri qu'un autre utilisateur ait changé l'ordre des feuilles.
Pour la suite, il suffit de lire les lignes une par une. Les lignes commencent à l'index « 0 », mais, puisqu'on va sauter les titres, on va ici commencer à l'index « 1 » :
@Override
public List<Chien> findAllChiens() {
final File file = new File(fileName);
final List<Chien> chiens = new ArrayList<Chien>();
try {
final Workbook workbook = WorkbookFactory.create(file);
final Sheet sheet = workbook.getSheet("Feuil1");
int index = 1;
Row row = sheet.getRow(index++);
while (row != null) {
final Chien chien = rowToChien(row);
chiens.add(chien);
row = sheet.getRow(index++);
}
} catch (InvalidFormatException | IOException e) {
e.printStackTrace();
}
return chiens;
}
private static Chien rowToChien(final Row row) {
...
}À ce stade, on peut déjà relancer les tests, ne serait-ce que pour vérifier qu'on trouve le bon nombre de chiens.
Il ne reste plus qu'à écrire la méthode qui prend une ligne pour la convertir en chien. La bibliothèque permet de lire directement le bon type dans les cellules :
private static Chien rowToChien(final Row row) {
final SimpleChien chien = new SimpleChien();
final String nom = row.getCell(0).getStringCellValue();
chien.setNom(nom);
final String nomComplet = row.getCell(1).getStringCellValue();
chien.setNomComplet(nomComplet);Pour le sexe, qui est représenté par la valeur « 1 » ou « 2 », il faut utiliser la méthode « getNumericCellValue » en faisant attention au fait qu'elle renvoie un double qu'il faudra donc convertir :
private static Chien rowToChien(final Row row) {
final SimpleChien chien = new SimpleChien();
final String nom = row.getCell(0).getStringCellValue();
chien.setNom(nom);
final String nomComplet = row.getCell(1).getStringCellValue();
chien.setNomComplet(nomComplet);
final int codeSexe = (int) row.getCell(2).getNumericCellValue();
final Sexe sexe = Sexe.valueOfByCode(codeSexe);
chien.setSexe(sexe);
final String codeRace = row.getCell(3).getStringCellValue();
final RaceDeChien race = RaceDeChien.valueOfByCode(codeRace);
chien.setRace(race);
final String couleurs = row.getCell(4).getStringCellValue();
chien.setCouleurs(stringToList(couleurs));
final double poids = row.getCell(5).getNumericCellValue();
chien.setPoids(poids);
return chien;
}Quand on relance les tests, tout est vert. On est donc légitimement en droit de penser qu'on a fini…
Le code du projet à cette étape est disponible dans le fichier « article-poi-5-min-02.zip ».
À ce stade, il est intéressant d'insister sur le fait que POI sait déterminer le type de donnée d'une cellule :
Row row = sheet.getRow(index);
final Cell cell = row.getCell(i);
final int cellType = cell.getCellType();
switch (cellType) {
case Cell.CELL_TYPE_BLANK:
...
break;
case Cell.CELL_TYPE_ERROR:
final byte error = cell.getErrorCellValue();
...
break;
case Cell.CELL_TYPE_STRING:
final String stringValue = cell.getStringCellValue();
...
break;
case Cell.CELL_TYPE_NUMERIC:
final double numericValue = cell.getNumericCellValue();
...
break;
case Cell.CELL_TYPE_BOOLEAN:
final boolean booleanValue = cell.getBooleanCellValue();
...
break;
case Cell.CELL_TYPE_FORMULA:
final String formula = cell.getCellFormula();
...
break;
}Vous remarquez qu'on peut lire une cellule de type formule. La valeur lue sera la formule et non le résultat de la formule. Si c'est le résultat qui nous intéresse, il faut évaluer la formule comme suit.
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
...
CellValue cellValue = evaluator.evaluate(cell);
int age = (int) cellValue.getNumberValue();III-D. Modification et écriture d'un fichier▲
Durée estimée : 2 minutes.
Maintenant qu'on sait lire un fichier, on a envie d'aller plus loin. Dans la suite, je vais partir du fichier qu'on vient de lire, je vais ajouter une colonne intitulée « Prix » et j'enregistrerai le fichier sous un autre nom.
Reprenons la lecture pour commencer. On peut la résumer au code suivant :
private static final String fileName1 = "src/test/resources/chien-01.xlsx";
@Test
public void testAjoutPrix() throws Exception {
final File file1 = new File(fileName1);
// Lecture fichier original
final Workbook workbook = WorkbookFactory.create(file1);
final Sheet sheet = workbook.getSheet("Feuil1");
final Row titreRow = sheet.getRow(0);
int index = 1;
Row row = sheet.getRow(index++);
while (row != null) {
...
row = sheet.getRow(index++);
}
}Dans un premier temps, je vais ajouter une colonne (juste une cellule en fait) avec le titre « Prix » :
@Test
public void testAjoutPrix() throws Exception {
...
// Ajout d'une cellule
final Row titreRow = sheet.getRow(0);
final Cell prixTitreCell = titreRow.createCell(6);
prixTitreCell.setCellValue("Prix");Je veux maintenant remplir les valeurs de cette colonne pour chaque ligne. Dans une animalerie classique, le prix d'un chien dépend généralement de sa race. On pourra donc écrire un code ressemblant au suivant :
@Test
public void testAjoutPrix() throws Exception {
...
// Modifications
int index = 1;
Row row = sheet.getRow(index++);
while (row != null) {
final String codeRace = row.getCell(3).getStringCellValue();
final RaceDeChien race = RaceDeChien.valueOfByCode(codeRace);
double prix = 0;
switch (race) {
case CANICHE:
prix = 99.00;
break;
case BASSET_ALPES:
case HARRIER:
prix = 150.00;
break;
case GOLDEN:
prix = 899.99;
break;
default:
prix = 450.00;
break;
}
final Cell prixCell = row.createCell(6);
prixCell.setCellValue(prix);
row = sheet.getRow(index++);
}Oui, c'est normal que les caniches soient moins chers que les autres, car ils sont plus petits ;-)
Il ne reste plus qu'à enregistrer tout ça :
private static final String fileName1 = "src/test/resources/chien-01.xlsx";
private static final String fileName2 = "src/test/resources/chien-02.xlsx";
@Test
public void testAjoutPrix() throws Exception {
...
// Ecriture dans un autre fichier
final File file2 = new File(fileName2);
final FileOutputStream fos = new FileOutputStream(file2);
workbook.write(fos);
fos.close();
}III-E. Un peu de style▲
Durée estimée : 2 minutes.
Pour le moment, le fichier n'est pas très joli. On va donc lui appliquer un peu de style. On commence avec la cellule du titre « Prix » à laquelle on va appliquer le même style que pour les autres titres :
@Test
public void testAjoutPrix() throws Exception {
...
// Ajout d'une cellule
final Row titreRow = sheet.getRow(0);
final Cell prixTitreCell = titreRow.createCell(6);
prixTitreCell.setCellValue("Prix");
final Cell nomCell = titreRow.getCell(0);
final CellStyle nomCellStyle = nomCell.getCellStyle();
prixTitreCell.setCellStyle(nomCellStyle);Il n'y a pas beaucoup de chiens dans l'exemple. S'il y en avait plus, il serait difficile de bien distinguer les lignes. On va donc en mettre une sur deux en couleur :
@Test
public void testAjoutPrix() throws Exception {
...
// Style
final CellStyle pairStyle = workbook.createCellStyle();
pairStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
pairStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
...
while (row != null) {
...
// Coloriage d'une ligne sur deux
if (index % 2 == 0) {
for (int i = 0; i < 7; i++) {
row.getCell(i).setCellStyle(pairStyle);
}
}
}Ici, je n'ai colorié que les cellules qui m'intéressaient. On peut aussi colorier la ligne entière, mais je trouve ça moins joli…
J'utilise la méthode « setFillForegroundColor() » à ne pas confondre avec « setFillBackgroundColor() ». La Doc de POI indique qu'on doit définir le « foreground » avant le « background ».
Le code du projet à cette étape est disponible dans le fichier « article-poi-5-min-03.zip ».
Avant de conclure, je voudrais attirer votre attention sur le fait que POI gère les cellules vides, ou inexistantes, d'une façon déconcertante. Lorsqu'on ouvre une feuille de calcul dans Excel, on a l'impression qu'il y a des cellules à l'infini horizontalement comme verticalement. Mais ce n'est pas comme ça que POI fonctionne. Si on essaie d'atteindre une cellule vide, pour la colorier par exemple, ça ne marchera pas. Pour contrer ce problème, il faut passer un second paramètre au getter pour indiquer le comportement à adopter en cas d'une cellule vide ou inexistante :
// row.getCell(i).setCellStyle(pairStyle);
row.getCell(i, Row.CREATE_NULL_AS_BLANK).setCellStyle(pairStyle);IV. Conclusion▲
Allez, on a déjà bien dépassé le contrat des « 5 minutes ». On va s'arrêter là car c'est largement suffisant pour comprendre comment fonctionne la bibliothèque Apache POI. Vous avez pu constater que c'est relativement simple.
Bien entendu, les fonctionnalités que nous avons découvertes sont relativement simples et POI sait faire bien plus que cela. Nous avons néanmoins vu celles qui me semblent être les plus importantes et que vous utiliserez à coup sûr dans vos projets. Vous avez toutes les cartes en main.
Voici tout de même quelques pistes si vous décidez d'approfondir la découverte d'Apache POI. La bibliothèque permet de :
- manipuler les formules, la mise en page, mises en forme conditionnelles, etc. ;
- utiliser des API à la SAX/StAX (eventmodel / streaming) ;
- travailler avec l'ancien format Excel (.xls) ;
- avoir une API générique qui abstrait en partie le format utilisé (.xls ou .xlsx) ;
- manipuler d'autres types de documents Office (Word, PowerPoint, Publisher, Outlook, Visio).
En outre, si vous prévoyez de créer de nombreux fichiers Excel, par exemple pour générer des factures, des bons de commande ou encore des documents administratifs, je vous conseille d'utiliser des modèles (templates), c'est-à-dire des documents Excel qui contiennent déjà toute la mise en forme, les titres, les couleurs, les formules, etc.
Vos retours nous aident à améliorer nos publications. N'hésitez donc pas à commenter cet article sur le forum : 6 commentaires ![]()
V. Remerciements▲
D'abord j'adresse mes remerciements à l'équipe POI, chez Apache, pour avoir développé une bibliothèque aussi utile et pour la maintenir. Je n'oublie pas tous les contributeurs qui participent notamment sur le forum.
Plus spécifiquement en ce qui concerne cet article, je tiens à remercier l'équipe de Developpez.com et plus particulièrement à Séb Piller, tchize_, OButterlin, Logan, Alain Bernard, Mickael Baron et Cédric Duprez.
VI. Annexes▲
VI-A. Liens▲
Apache POI : http://poi.apache.org
VI-B. Liens personnels▲
Retrouvez ma page et mes autres articles sur Developpez.com à l'adresse https://thierry-leriche-dessirier.developpez.com/#page_articles
Suivez-moi sur Twitter : @thierryleriche (https://twitter.com/thierryleriche)
Et sur mon site ICAUDA : http://www.icauda.com
VI-C. Codes sources complets▲
package com.icauda.article.poi.chien.dao;
import static com.icauda.article.poi.chien.domain.RaceDeChien.BERGER_ALLEMAND;
import static com.icauda.article.poi.chien.domain.RaceDeChien.CANICHE;
import static com.icauda.article.poi.chien.domain.RaceDeChien.GOLDEN;
import static com.icauda.article.poi.chien.domain.RaceDeChien.ROTTWEILER;
import java.util.List;
import org.apache.log4j.Logger;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.icauda.article.poi.chien.domain.Chien;
import com.icauda.article.poi.chien.domain.RaceDeChien;
public class PoiChienDaoTest {
private static final Logger log = Logger.getLogger(PoiChienDaoTest.class);
private static final String fileName = "src/test/resources/chien-01.xlsx";
private ChienDao dao;
@Before
public void doBefore() {
dao = new PoiChienDao(fileName);
}
@Test
public void testFindAllchien() {
log.debug("testFindAllchien");
// Arrange
final int expectedSize = 5;
// Act
final List<Chien> chiens = dao.findAllChiens();
// Assert
Assert.assertNotNull(chiens);
Assert.assertEquals(expectedSize, chiens.size());
}
@Test
public void testOrdreDesChiens() {
log.debug("testFindAllchien");
// Arrange
final String[] expectedNoms = { "Milou", "Pluto", "Lassie", "Volt", "Medor" };
// Act
final List<Chien> chiens = dao.findAllChiens();
// Assert
for (int i = 0; i < expectedNoms.length; i++) {
Assert.assertEquals(expectedNoms[i], chiens.get(i).getNom());
}
}
@Test
public void testTaillesDesChiens() {
log.debug("testFindAllchien");
// Arrange
final double[] expectedPoids = { 12.5, 24, 32.3, 14, 32 };
// Act
final List<Chien> chiens = dao.findAllChiens();
// Assert
for (int i = 0; i < expectedPoids.length; i++) {
Assert.assertEquals(expectedPoids[i], chiens.get(i).getPoids().doubleValue(), 0.001d);
}
}
@Test
public void testRacesDesChiens() {
log.debug("testFindAllchien");
// Arrange
final RaceDeChien[] expectedRaces = { CANICHE, GOLDEN, BERGER_ALLEMAND, CANICHE, ROTTWEILER };
// Act
final List<Chien> chiens = dao.findAllChiens();
// Assert
for (int i = 0; i < expectedRaces.length; i++) {
Assert.assertEquals(expectedRaces[i], chiens.get(i).getRace());
}
}
}package com.icauda.article.poi.chien.dao;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
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.ss.usermodel.WorkbookFactory;
import com.icauda.article.poi.chien.domain.Chien;
import com.icauda.article.poi.chien.domain.RaceDeChien;
import com.icauda.article.poi.chien.domain.Sexe;
import com.icauda.article.poi.chien.domain.SimpleChien;
public class PoiChienDao implements ChienDao {
private static final Logger log = Logger.getLogger(PoiChienDao.class);
private String fileName;
public PoiChienDao(final String fileName) {
super();
this.fileName = fileName;
}
@Override
public List<Chien> findAllChiens() {
final File file = new File(fileName);
final List<Chien> chiens = new ArrayList<Chien>();
try {
final Workbook workbook = WorkbookFactory.create(file);
final Sheet sheet = workbook.getSheet("Feuil1");
int index = 1;
Row row = sheet.getRow(index++);
while (row != null) {
final Chien chien = rowToChien(row);
chiens.add(chien);
row = sheet.getRow(index++);
}
} catch (InvalidFormatException | IOException e) {
log.error(e.getMessage(), e);
// e.printStackTrace();
}
return chiens;
}
private static Chien rowToChien(final Row row) {
final SimpleChien chien = new SimpleChien();
final String nom = row.getCell(0).getStringCellValue();
chien.setNom(nom);
final String nomComplet = row.getCell(1).getStringCellValue();
chien.setNomComplet(nomComplet);
final int codeSexe = (int) row.getCell(2).getNumericCellValue();
final Sexe sexe = Sexe.valueOfByCode(codeSexe);
chien.setSexe(sexe);
final String codeRace = row.getCell(3).getStringCellValue();
final RaceDeChien race = RaceDeChien.valueOfByCode(codeRace);
chien.setRace(race);
final String couleurs = row.getCell(4).getStringCellValue();
chien.setCouleurs(stringToList(couleurs));
final double poids = row.getCell(5).getNumericCellValue();
chien.setPoids(poids);
return chien;
}
private static List<String> stringToList(final String s) {
final List<String> couleurs = new ArrayList<String>();
// TODO ... Utilise le Splitter de Guava...
return couleurs;
}
}package com.icauda.article.poi.chien.dao;
import java.io.File;
import java.io.FileOutputStream;
import org.apache.log4j.Logger;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
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.ss.usermodel.WorkbookFactory;
import org.junit.Before;
import org.junit.Test;
import com.icauda.article.poi.chien.domain.RaceDeChien;
public class PoiChienDao2Test {
private static final Logger log = Logger.getLogger(PoiChienDaoTest.class);
private static final String fileName1 = "src/test/resources/chien-01.xlsx";
private static final String fileName2 = "src/test/resources/chien-02.xlsx";
@Before
public void doBefore() {
}
@Test
public void testAjoutPrix() throws Exception {
log.debug("testAjoutPrix");
final File file1 = new File(fileName1);
// Lecture fichier original
final Workbook workbook = WorkbookFactory.create(file1);
final Sheet sheet = workbook.getSheet("Feuil1");
// Ajout d'une cellule
final Row titreRow = sheet.getRow(0);
final Cell prixTitreCell = titreRow.createCell(6);
prixTitreCell.setCellValue("Prix");
final Cell nomCell = titreRow.getCell(0);
final CellStyle nomCellStyle = nomCell.getCellStyle();
prixTitreCell.setCellStyle(nomCellStyle);
// Style
final CellStyle pairStyle = workbook.createCellStyle();
pairStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
pairStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
// Modifications
int index = 1;
Row row = sheet.getRow(index++);
while (row != null) {
final String codeRace = row.getCell(3).getStringCellValue();
final RaceDeChien race = RaceDeChien.valueOfByCode(codeRace);
double prix = 0;
switch (race) {
case CANICHE:
prix = 99.00;
break;
case BASSET_ALPES:
case HARRIER:
prix = 150.00;
break;
case GOLDEN:
prix = 899.99;
break;
default:
prix = 450.00;
break;
}
final Cell prixCell = row.createCell(6);
prixCell.setCellValue(prix);
// Coloriage d'une ligne sur deux
if (index % 2 == 0) {
for (int i = 0; i < 7; i++) {
row.getCell(i).setCellStyle(pairStyle);
}
}
row = sheet.getRow(index++);
}
// Écriture dans un autre fichier
final File file2 = new File(fileName2);
// Comme je lance le test plusieurs fois, je pars d'une copie blanche a chaque fois.
if (file2.exists()) {
file2.delete();
}
final FileOutputStream fos = new FileOutputStream(file2);
workbook.write(fos);
fos.close();
}
}public class SimpleChien implements Chien {
private String nom;
private String nomComplet;
private Sexe sexe;
private RaceDeChien race;
private List<String> couleurs;
private Double poids;
public SimpleChien() {
// rien...
}
public SimpleChien(final String nom) {
this.nom = nom;
}
public SimpleChien(final String nom, final RaceDeChien race, final Sexe sexe) {
this(nom);
this.race = race;
this.sexe = sexe;
}
@Override
public String toString() {
return "SimpleChien [nom=" + nom + "]";
}
// Getters et setterspublic enum Sexe {
FEMALE(2), //
MALE(1);
private final int code;
Sexe(final int code) {
this.code = code;
}
public static Sexe valueOfByCode(final int code) {
switch (code) {
case 2:
return FEMALE;
case 1:
return MALE;
default:
throw new IllegalArgumentException("Le sexe demande n'existe pas.");
}
}
public boolean isMale() {
return this == MALE;
}
public int getCode() {
return code;
}
}public enum RaceDeChien {
BASSET_ALPES("Basset des Alpes", "basset_alp"), //
BERGER_ALLEMAND("Berger allemand", "berger_all"), //
CANICHE("Caniche", "caniche"), //
HARRIER("Harrier", "harrier"), //
GOLDEN("Golden retriever", "golden_ret"), //
ROTTWEILER("Rottweiler", "rottweiler"), //
WESTIE("Westie", "westie");
private final String label;
private final String code;
RaceDeChien(final String label, final String code) {
this.label = label;
this.code = code;
}
public static RaceDeChien valueOfByCode(final String code) {
if (code == null || code.isEmpty()) {
throw new IllegalArgumentException("Le code ne peut pas etre vide.");
}
for (RaceDeChien race : values()) {
if (race.code.equalsIgnoreCase(code)) {
return race;
}
}
throw new IllegalArgumentException("La race de chien demandee n'existe pas.");
}
public String getLabel() {
return label;
}
public String getCode() {
return code;
}
}







