"Je veux sortir Excel en Java, mais je ne veux pas le spécifier par numéro de cellule comme Apache POI", "Je veux une bibliothèque de niveau légèrement supérieur", j'ai trouvé une bibliothèque appelée XlsMapper, alors je l'ai essayé C'était. Veuillez signaler toute erreur ou conseil de mise en œuvre.
Une bibliothèque Java qui mappe Excel à Java. Il y avait autrefois une célèbre bibliothèque Java appelée XLSBeans qui a été transformée en livre, mais son développement semble s'être arrêté. Sur la base de cette version 1.1, il semble que les individus ajoutent progressivement des fonctions comme un autre projet XlsMapper. (En fait, j'ai utilisé XLS Beans pendant un certain temps.)
Lors de l'accès à Excel en utilisant POI, pour la liste extraite de la base de données (si vous connaissez les informations), Enregistrer 1. Définissez et mettez en forme l'élément 1 dans la cellule de la colonne Mth du Nième enregistrement dans Excel. Enregistrer 1. Définissez et formatez l'élément 2 dans la cellule de la colonne M + 1ère du Nième enregistrement d'Excel. : Enregistrer 2. Définissez et mettez en forme l'élément 1 dans la cellule de la colonne Mth de N + 1er enregistrement dans Excel. :
Si vous devez implémenter un accès comme celui-ci, ou si la structure de la colonne change, vous devrez décaler les valeurs N et M en conséquence. Avec cette bibliothèque, vous pouvez mapper les valeurs Excel aux POJO et écrire les POJO mappés vers Excel, tout comme un mappeur OR, réduisant ainsi les descriptions de traitement inutiles. De plus, il n'est pas nécessaire de se soucier d'implémenter le format, etc. car les paramètres tels que la copie de l'enregistrement précédent peuvent être définis avec des annotations.
Maven Ajoutez ce qui suit à pom. * Omis sauf pour les éléments liés à Excel.
pom.xml
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>com.github.mygreen</groupId>
<artifactId>xlsmapper</artifactId>
<version>2.0</version>
</dependency>
Préparez un livre avec le tableau suivant. Le but est de fermer la table avec une ligne réglée.
SpringBootApplication
DemoService.java
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
//Renvoyez simplement l'argument sous forme de carte
CommandLineParamsMap params = new CommandLineParamsMap(args);
try (ConfigurableApplicationContext ctx = SpringApplication.run(DemoApplication.class, args)) {
DemoService app = ctx.getBean(DemoService.class);
app.execute(params);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Service
DemoService.java
@Service
@Slf4j
public class DemoService {
private static final String TEMPLATE_FILE_PATH = "template\\Liste d'utilisateur_%s année%s mois%création du jour.xlsx";
private static final String OUTPUT_FILE_PATH = "C:\\test\\Liste d'utilisateur_%s année%s mois%création du jour.xlsx";
public String execute(CommandLineParamsMap params) {
log.info("DemoService START");
LocalDate outPutDate = getOutPutDate(params.getValue("date"));
log.info("date:" + outPutDate);
String outputPath = makeTargetPath(outPutDate);
//Obtenir des données de table
List<UsingListRecord> target = getData();
//Définissez chaque information dans la feuille
UsingListSheet sheet = new UsingListSheet();
sheet.setOutPutDate("Date de sortie:" + outPutDate);
sheet.setRecords(target);
//Ajouter la ligne totale de formule à la dernière ligne
sheet.addSummaryRecord();
XlsMapper xlsMapper = new XlsMapper();
try {
//Écrivez ceci (aucune boucle requise)!
xlsMapper.save(
new FileInputStream(TEMPLATE_FILE_PATH), //Fichier Excel du modèle
new FileOutputStream(outputPath), //Fichier Excel à écrire
sheet //Données créées
);
} catch (XlsMapperException | IOException e) {
throw new RuntimeException(e);
}
//Lisez le tableau écrit et essayez de sortir
List<UsingListRecord> records = read(outputPath);
records.forEach(r->log.info(r.toString()));
log.info("DemoService END");
return "###########success###########";
}
/**
*aaaammjj → objet LocalDate
* @param value
* @return
*/
private LocalDate getOutPutDate(String value) {
int year = Integer.parseInt(value.substring(0, 4));
int month = Integer.parseInt(value.substring(4, 6));
int day = Integer.parseInt(value.substring(6, 8));
return LocalDate.of(year, month, day);
}
//L'acquisition des données
private List<UsingListRecord> getData() {
//En fait, apportez-le de DB
List<UsingListRecord> list = new ArrayList<>();
list.add(getSample("Anakin Skywalker", "Tatween", "Humain", 100, "Asoka Tano", 1));
list.add(getSample("Padme Amidara", "Naboo", "Humain", 100, null, 2));
list.add(getSample("Luke Skywalker", "Police Masa", "Humain", 100, "Caire Ren", 3));
list.add(getSample("Caire Ren", "Chandrila", "Humain", 100, null, 4));
list.add(getSample("Asoka Tano", "Siri", "Togruta", 100, null, 5));
list.add(getSample("Darth Mall", "Dasomie", "Zabrak", null, "Opres sauvages", 6));
list.add(getSample("Yoda", null, "Yodaの種族", 800, "Luke Skywalker", 7));
return list;
}
//Renvoie un exemple d'enregistrement approprié
private UsingListRecord getSample(String name, String homeTown, String species, Integer ageAvg, String apprentice,
int i) {
LocalDate d1 = LocalDate.of(2019, 3, 1).plusDays(i);
Date startDate = Date.from(d1.atStartOfDay(ZoneId.systemDefault()).toInstant());
UsingListRecord record = new UsingListRecord();
record.setUserName(name);
record.setPrice(new BigDecimal(120000 + i));
record.setTax(0.08d + i);
record.setUsingStartDate(startDate);
record.setHomeTown(homeTown);
record.setSpecies(species);
record.setAgeAvg(ageAvg);
record.setApprentice(apprentice);
return record;
}
private List<UsingListRecord> read(String targetPath) {
XlsMapper xlsMapper = new XlsMapper();
UsingListSheet sheet = null;
try {
sheet = xlsMapper.load(
new FileInputStream(targetPath), //Fichier Excel à lire
UsingListSheet.class //Classe annotée.
);
} catch (XlsMapperException | IOException e) {
throw new RuntimeException(e);
}
return sheet.getRecords();
}
private String makeTargetPath(LocalDate batchDate) {
return String.format(OUTPUT_FILE_PATH,
batchDate.getYear(),
batchDate.getMonthValue(),
batchDate.getDayOfMonth()
);
}
}
Sheet Une classe qui représente une feuille. Donnez @XlsSheet (nom = "nom de la feuille").
UsingListSheet.java
@Slf4j
@Data
@XlsSheet(name = "Liste d'utilisateur")
public class UsingListSheet {
private String outPutDate;
@XlsHorizontalRecords(tableLabel = "Liste d'utilisateur", bottom = 3)
@XlsRecordOption(overOperation = OverOperation.Copy)
private List<UsingListRecord> records;
public void addSummaryRecord() {
if (records == null) {
this.records = new ArrayList<>();
}
UsingListRecord record = new UsingListRecord();
//Passez votre propre instance
record.setParent(this);
record.setUserName("total");
records.add(record);
}
/**
*Après avoir écrit le tableau, essayez de régler la date de sortie avec POI.
* @param sheet
*/
@XlsPostSave
public void aa(final Sheet sheet) {
Cell cell = POIUtils.getCell(sheet, 7, 0);
CellStyle style=cell.getCellStyle();
cell.setCellValue(outPutDate);
cell.setCellStyle(style);
}
}
@XlsHorizontalRecords Définissez-le pour un type de tableau avec un en-tête ci-dessus, tel que l'Excel ci-dessous. Spécifiez le titre de la table avec tableLabel. Le bas spécifie la distance entre la table réelle et le tableLabel. S'il existe un en-tête de tableau directement sous tableLabel, il n'est pas nécessaire de le spécifier.
@XlsRecordOption(overOperation = OverOperation.Copy) Spécifiez ce qu'il faut faire lorsqu'il y a plus de lignes de données que le nombre de lignes spécifié dans le modèle (déterminé par la bordure). Dans le cas d'OverOperation.Copy, le format de la ligne un niveau supérieur est copié et une ligne est ajoutée. OverOperation.Insert corrompt le classeur. (Voir l'environnement que j'ai essayé ci-dessus pour la raison.)
@XlsPostSave La méthode avec ceci sera exécutée automatiquement après l'écriture du fichier. Il peut également être assigné à la méthode de la classe Record, et l'ordre est @XlsPostSave of Sheet → @XlsPostSave of Record. Il y a beaucoup d'autres choses telles que @XlsPreSave, alors voyez ci-dessous. 7. Gestion des événements du cycle de vie
Record Une classe qui représente un enregistrement de la table à placer sur la feuille Excel.
UsingListRecord.java
@Data
public class UsingListRecord {
//Informations de localisation mappées
private Map<String, CellPosition> positions;
//Informations sur le bean parent
private UsingListSheet parent;
@XlsColumn(columnName = "Utilisateur")
private String userName;
@XlsColumn(columnName = "Frais")
@XlsFormula(methodName = "getSumFormula", primary = false)
private BigDecimal price;
@XlsColumn(columnName = "taux de taxe de vente")
private Double tax;
@XlsColumn(columnName = "Date de début d'utilisation")
@XlsDateTimeConverter(excelPattern = "yyyy/m/d")
private Date usingStartDate;
@XlsColumn(columnName = "Lieu de naissance")
@XlsDefaultValue(value="--", cases=ProcessCase.Save)
private String homeTown;
@XlsColumn(columnName = "Course")
private String species;
@XlsColumn(columnName = "Vie moyenne")
private Integer ageAvg;
@XlsColumn(columnName = "Disciple")
@XlsDefaultValue(value="--", cases=ProcessCase.Save)
private String apprentice;
//Assemblez la formule totale
public String getSumFormula(Point point) {
//Formule de sortie uniquement lorsque la ville natale est totale
if (!userName.equals("total")) {
return null;
}
//Taille de l'enregistrement (valeur recherchant les totaux dans la ligne d'enregistrement)
final int dataSize = parent.getRecords().size() - 1;
//Nom de colonne
final String colAlpha = CellReference.convertNumToColString(point.x);
//Début de la valeur totale/Numéro de ligne de fin
final int startRowNumber = point.y - dataSize + 1;
final int endRowNumber = point.y;
return String.format("SUM(%s%d:%s%d)", colAlpha, startRowNumber, colAlpha, endRowNumber);
}
}
@XlsFormula En spécifiant primary = false, s'il y a une valeur dans le champ correspondant, elle sera prioritaire. Si c'est vrai, la formule a toujours la priorité.
@XlsDefaultValue Définissez la valeur par défaut de NULL avec value. Si cases = ProcessCase.Save est spécifié, la valeur par défaut sera définie uniquement pour l'écriture.
Entrez "date = 20190312" comme argument dans la configuration d'exécution de l'application Springboot, appliquez et exécutez.
Si vous regardez la fenêtre de formule, la formule est également sortie correctement.
Journal lors de la lecture du tableau après l'écriture. L'acquisition se fait correctement.
Journal (extrait)
com.example.demo.service.DemoService : date:2019-03-12
com.example.demo.service.DemoService : UsingListRecord(positions={userName=A5, price=B5, tax=C5, usingStartDate=D5, homeTown=E5, species=F5, ageAvg=G5, apprentice=H5}, parent=null, userName=Anakin Skywalker, price=120001, tax=1.08, usingStartDate=Sat Mar 02 00:00:00 JST 2019, homeTown=Tatween, species=Humain, ageAvg=100, apprentice=Asoka Tano)
com.example.demo.service.DemoService : UsingListRecord(positions={userName=A6, price=B6, tax=C6, usingStartDate=D6, homeTown=E6, species=F6, ageAvg=G6, apprentice=H6}, parent=null, userName=Padme Amidara, price=120002, tax=2.08, usingStartDate=Sun Mar 03 00:00:00 JST 2019, homeTown=Naboo, species=Humain, ageAvg=100, apprentice=--)
com.example.demo.service.DemoService : UsingListRecord(positions={userName=A7, price=B7, tax=C7, usingStartDate=D7, homeTown=E7, species=F7, ageAvg=G7, apprentice=H7}, parent=null, userName=Luke Skywalker, price=120003, tax=3.08, usingStartDate=Mon Mar 04 00:00:00 JST 2019, homeTown=Police Masa, species=Humain, ageAvg=100, apprentice=Caire Ren)
com.example.demo.service.DemoService : UsingListRecord(positions={userName=A8, price=B8, tax=C8, usingStartDate=D8, homeTown=E8, species=F8, ageAvg=G8, apprentice=H8}, parent=null, userName=Caire Ren, price=120004, tax=4.08, usingStartDate=Tue Mar 05 00:00:00 JST 2019, homeTown=Chandrila, species=Humain, ageAvg=100, apprentice=--)
com.example.demo.service.DemoService : UsingListRecord(positions={userName=A9, price=B9, tax=C9, usingStartDate=D9, homeTown=E9, species=F9, ageAvg=G9, apprentice=H9}, parent=null, userName=Asoka Tano, price=120005, tax=5.08, usingStartDate=Wed Mar 06 00:00:00 JST 2019, homeTown=Siri, species=Togruta, ageAvg=100, apprentice=--)
com.example.demo.service.DemoService : UsingListRecord(positions={userName=A10, price=B10, tax=C10, usingStartDate=D10, homeTown=E10, species=F10, ageAvg=G10, apprentice=H10}, parent=null, userName=Darth Mall, price=120006, tax=6.08, usingStartDate=Thu Mar 07 00:00:00 JST 2019, homeTown=Dasomie, species=Zabrak, ageAvg=null, apprentice=Opres sauvages)
com.example.demo.service.DemoService : UsingListRecord(positions={userName=A11, price=B11, tax=C11, usingStartDate=D11, homeTown=E11, species=F11, ageAvg=G11, apprentice=H11}, parent=null, userName=Yoda, price=120007, tax=7.08, usingStartDate=Fri Mar 08 00:00:00 JST 2019, homeTown=--, species=Yodaの種族, ageAvg=800, apprentice=Luke Skywalker)
com.example.demo.service.DemoService : UsingListRecord(positions={userName=A12, price=B12, tax=C12, usingStartDate=D12, homeTown=E12, species=F12, ageAvg=G12, apprentice=H12}, parent=null, userName=total, price=840028, tax=null, usingStartDate=null, homeTown=--, species=null, ageAvg=null, apprentice=--)
J'ai remarqué qu'il a été mis en œuvre, mais il est également bon que le processus de clôture ne soit pas nécessaire. Cette fois, c'est devenu un peu compliqué car le processus de sortie de la formule (ligne totale) est inclus dans l'enregistrement final, mais s'il n'y a pas de formule, la méthode n'est pas nécessaire pour les classes Sheet et Record, et l'annotation est réduite et c'est assez simple. Devenir.
Recommended Posts