Come progettare una classe di esportazione Excel in MVC?

0

Ho un sistema piuttosto mal progettato proprio ora scritto in ASP.NET MVC.

Ha implementato molta logica all'interno dei controller senza alcun modello esterno con logica di business. Mi piacerebbe cambiarlo un po 'e scrivere una classe che sarebbe in grado di esportare alcune tabelle dalle viste in Excel. La maggior parte delle visualizzazioni che richiederebbero questa funzionalità non hanno nulla in comune e non sono sicuro di come affrontarla.

Posso ad esempio passare il contesto del database (Entity Framework) dal controller come parametro o dovrei ottenere informazioni sul modello all'interno del controller e trasmetterlo al metodo? Devo creare un modello di classe che ottenga tutte le informazioni necessarie per creare un file Excel e passare le informazioni all'interno del controller?

    
posta feni000 26.07.2017 - 11:23
fonte

1 risposta

1

Ci sono diversi modi per farlo. Una risposta accurata potrebbe portarci a conoscere più dettagliatamente il design attuale. Tuttavia, ho dovuto fare qualcosa di simile recentemente che ha funzionato bene e mi ha portato meno componenti del previsto.

Prima di tutto, per quanto riguarda le 2 opzioni possibili, il 2 nd mi sembra più pulito perché consente di disaccoppiare il modello attuale dalla nuova funzione. Di solito evito di consentire ai Controller di accedere al livello di persistenza, quindi al momento non andrei in quel modo (# 1).

Come ho commentato, ho implementato qualcosa di simile di recente. Al momento di prendere una decisione, ho deciso di implementare la soluzione meno tipizzata possibile. Con digitato intendo, la soluzione che richiedeva meno classi o interfacce. Questo mi ha portato ad affrontare il problema da un punto di vista convention over configuration . Mi è venuta l'idea di come supportassimo altri formati di rappresentazione come JSON o XML.

L'obiettivo è riutilizzare il modello attuale in modo tale da non dover modificarlo drasticamente, alterarne la gerarchia attuale o avvolgerlo con nuove classi.

Invece di digitare la soluzione con nuove interfacce o classi - che nella maggior parte dei casi non vanno d'accordo con il nostro modello attuale- 3 , usiamo Attributi o Annotazioni.

Visto che non ho familiarità con C #, se non ti dispiace, illustrerò la risposta con Java e @Annotations.

@JacksonXmlRootElement(localName = "kpi-accounts")
@JsonRootName("kpi-accounts")
@XlsxSheetProperty(name = "accounts")
public class KPIAccountsTO implements Serializable {

    private static final long serialVersionUID = 1L;    
    private int active;
    private int onBoardingPending;
    private int notActive;

    // Constructor and setters omitted for brevity ...

    @JacksonXmlProperty(localName = "active")
    @JsonProperty(value = "active", index = 0)
    @XlsxColumnProperty(name = "active", index = 0)
    public int getActive() {
        return active;
    }

    @JacksonXmlProperty(localName = "on-boarding-pending")
    @JsonProperty(value = "on-boarding-pending", index = 1)
    @XlsxColumnProperty(name = "on-boarding-pending", index = 1, widthModifier = 2)
    public int getOnBoardingPending() {
        return onBoardingPending;
    }           

    @JacksonXmlProperty(localName = "not-active")
    @JsonProperty(value = "not-active", index = 2)
    @XlsxColumnProperty(name = "not-active", index = 2)
    public int getNotActive() {
        return notActive;
    }       

}

Fai attenzione alle annotazioni @XlsxColumnProperty e @XlsxSheetProperty . 1

Di solito, non difendo a favore del riflesso ma, in questo caso, funziona come un incantesimo.

Caricamento @XlsxSheetProperty per la creazione del foglio e dei relativi metadati.

public static XSSFSheet createDefaultSheet(XSSFWorkbook book, Class<?> clazzHeader) {
        XlsxSheetProperty sheetAnnotation = clazzHeader.getAnnotationsByType(XlsxSheetProperty.class)[0];
        XSSFSheet sheet = book.createSheet(sheetAnnotation.name().toUpperCase());
        ...
        createRowHeder(sheet, clazzHeader);
        return sheet;
    }

Caricamento @XlsxColumnProperty per il popolamento dell'intestazione. 2

private static XSSFRow createRowHeder(XSSFSheet sheet, Class<?> clazzHeader) {
        XSSFRow header = sheet.createRow(0);            
        Method[] methods = Arrays.stream(clazzHeader.getMethods())
                .filter(method -> method.isAnnotationPresent(XlsxColumnProperty.class))
                // Sorted by index
                .sorted((m1, m2) -> Integer.compare(
                        // m1
                        m1.getAnnotation(XlsxColumnProperty.class).index(),
                        // m2
                        m2.getAnnotation(XlsxColumnProperty.class).index()))
                .toArray(size -> new Method[size]);

        //TODO: Move the stream pipeline
        for (int idx = 0; idx < methods.length; idx++) {
            XlsxColumnProperty annotation = methods[idx].getAnnotation(XlsxColumnProperty.class);
            createDefaultCell(idx, header).setCellValue(annotation.name().toUpperCase());
            sheet.setColumnWidth(idx, sheet.getColumnWidth(idx) * annotation.widthModifier());
        }
        return header;
    }

Rimanere da risolvere come mappare i campi entità alle colonne del foglio. L'ordine, come puoi vedere, è già fornito dall'annotazione , quindi l'ultimo per decidere come ottenere i valori. Abbiamo due opzioni qui, mappers o reflection di nuovo. Se l'entità di esportazione è complessa, tendo ad implementare i mapper, per i POJO piatti come quello qui esposto, la riflessione è sufficiente.

Nota : Seguendo questo approccio mi sono permesso di creare cartelle di lavoro con fogli diversi, in cui ognuno di essi è modellato da un POCO diverso.

1: si noti che questo TO appartiene a un modello di dati API. La mia API supporta in realtà diversi formati, tra cui JSON e XML. Tuttavia, potrebbe essere anche il modello di visualizzazione di qualsiasi MVC.

2: Non presti troppa attenzione ai dettagli di implementazione. Sto ancora effettuando il refactoring del codice.

3: il più eterogeneo, il più duro

    
risposta data 26.07.2017 - 14:33
fonte

Leggi altre domande sui tag