CSVGenerator
O CSVGenerator tem o objeto de permitir a geração de arquivos CSV a partir da estrutura de dados utilizada pelo BIS. Aproveito a estrutura dos VOs e BISMetaObjects (VO_), isto é, aceita uma lista de VOs, e gera o arquivo CSV a partir das colunas selecionadas de dentro desses objetos.
Para exemplificar o funcionamento de todas as partes do CSVGenerator vamos imaginar que queremos exportar como CSV nosso cadastro de pessoas, lista de PersonVO.
CSVGeneratorOptions
O CSVGeneratorOptions carrega praticamente toda a configuração de como o arquivo deve ser gerado. Desta forma é possível realizar toda a definição em qualquer cama (UI por exemplo) e passar para o gerador de uma única vez. Permite que seja criado um componente único para manipular o objeto para as UIs e reaproveitado em todas as telas, útil principalmente quando o gerador ganha novas opções.
Entre as configurações básicas do arquivo estão:
- Delimitador - utilizado para separar os campos do arquivo
- Localidade - Define a localidade para formatação básica dos valores, como caractere de decimais, data, etc.
- Títulos das Colunas - Define se deve ser escrito uma linha no começo com os títulos das colunas.
- Valor de Nulo - Valor que deve ser utilizado caso o objeto tenha um valor nulo. Por padrão não é escrito nada, o equivalente á "", mas pode ser necessário distinguir o "" do null.
CSVGenerator
Todos os atributos de configuração já tem um valor padrão, de forma que para gerar um CSV, basta definir as colunas desejadas e passar a coleção de dados no método .generate().
![]() |
Exemplos de Uso
// Define as colunas no options
options.setColumns(new String[]{
PersonVO_.VO.displayname(),
PersonVO_.VO.fullname(),
PersonVO_.VO.cpfcnpj()
});
// Construtor vazio cria um CSVGeneratorOptions com a opções padrão. Mas depois tem que pegar o options para colocar as colunas ou terá um CSV vazio.
final CSVGenerator<PersonVO> gen = new CSVGenerator<PersonVO>(options);
// Retorna o CSV com as colunas selecionadas.
return gen.generate(personList);
|
![]() |
|
O arquivo foi gerado, mas muitas vezes não é o que desejamos. Agora para formatar, configurar e manipular os dados é que precisará de configurações adicionais.
Formatando os Dados
A formatação dos dados é feita de forma simples e de acordo com o locale passado. São formatados os números e datas apenas. De resto os campos são escritos utilizando o equivalente ao .toString() do objeto, e apenas dos objetos conhecidos pelo CSVGenerator, como String, BigDecimal, Enum, Float, Double, etc.. Outros formatos geram exception crítica para forçar um tratamento mais adequado do desenvolvedor.
O CSVGenerator permite a configuração das colunas utilizando a interface BISDataFormatter. Para isso defina a instância do BISDataFormatter desejado na coluna através do CSVGeneratorOptions:
![]() |
Exemplos de Uso
// inclui o formatador de cpf/cnpj na coluna com o valor do documento
options.getColumnFormatter().put(PersonVO_.VO.cpfcnpj(), BISCPFOrCNPJDataFormatter.getInstance());
|
![]() |
|
Processamento do Valor da Coluna
Em alguns casos desejamos realizar o processamento do valor da coluna, antes de passar pelo formatador, como por exemplo, caso o valor de uma determinada coluna seja truncado, ou seja realizado um arredondamento específico, etc.
Para estes casos devemos incluir um DataProcess, que nos fornecerá as informações necessárias para processarmos o valor conforme desejado.
![]() |
Exemplos de Uso
options.getColumnDataProcess().put(PersonVO_.VO.displayname(), new CSVColumnDataProcess() {
@Override
public Object getColumnValue(BISVO vo, String columnName, HashMap<String, Object> iterableCache) throws BISException {
String t = (String) BISUtilsReflex.getPropertyValue(vo, columnName);
// Trunca se tiver mais de 50 caracteres
if (t != null && t.length() > 50) t = t.substring(0, 50);
return t;
}
@Override
public String getColumnTitle(String columnName) {
// Retorna nulo para que seja recuperado normalmente pelo caption do BISAnnotation
return null;
}
});
|
![]() |
|
Colunas Personalizada
Nem sempre a informação que desejamos escrever no CSV está dentro do VO. Como por exemplo, se queremos escrever uma coluna de "Total", sendo o resultado do cálculo envolvendo outros valores que estão no VO, mas este valor não está no VO diretamente. Ou qualquer outra coluna com qualquer outro valor, até mesmo escrever o System.currentTimeMillis() para verificar a velocidade de geração dos dados. Qualquer que seja a informação a ser escrita, você deve usar o mesmo ColumnDataProcess explicado acima e retornar qualquer valor desejado.
Como o ColumnDataProcess é colocado sempre 'por cima' de uma coluna existente, podemos realizar de duas maneiras: incluir uma coluna qualquer que não esteja sendo utilizada (só recomendável se o valor manipulado for de alguma maneira uma variação do valor original), ou criar uma coluna com um id customizado (mais recomendado), como por exemplo:
![]() |
Exemplos de Uso
// Define as colunas no options
String columnTotal = "Total";
options.setColumns(new String[]{
...,
columnTotal,
...,
...
});
...
options.getColumnDataProcess().put(columnTotal, new CSVColumnDataProcess() {
...
});
|
Como as colunas com ColumnDataProcess não tentam resolver o valor no VO utilizando o ID da coluna, não resultará em erro.
![]() |
|
Agrupando Valores
Em alguns momentos temos os dados todos detalhados, como estão na tabela, mas queremos apresentar os dados de forma agrupada, similar a funcionalidade do 'group by' utilizado no SQL. Para esses casos o CSVGenerator tem uma funcionalidade que permite que os registros sejam agrupados de acordo com campos chaves. Por exemplo, um relatório de vendas, temos todas as vendas de itens detalhada uma a uma, mas queremos exportar um arquivo com apenas 1 linha para cada código para cada empresa. Neste caso devemos definir a coluna de código como chave do agrupamento:
![]() |
Exemplos de Uso
options.setGroupByColumns(new String[]{
companyColumnID,
codeColumnID
});
|
Desta forma, toda vez que o CSVGenerator encontrar um novo objeto com o mesmo valor na coluna companyColumnID e na codeColumnID, ela será "ignorada" já que já temos essa linha.
Funções de Agrupamento
O agrupamento de valores, conforme descrito acima, funciona bem se o objetivo for ter um funcionamento similar ao "Distinct" do SQL. Mas normalmente o agrupamento dos valores faz mais sentido quando desejamos "Sumarizar" os valores encontrados nas linhas repetidas. Se o caso for esse, devemos definir que função desejamos fazer com os outros valores um à um. Se for mesmo o caso de ir somando os valores a medida que as colunas chaves se repetem, devemos utilizar a função SUM. Definindo desta forma:
![]() |
Exemplos de Uso
// Faz com que os valores da coluna sejam todos somados a medida que as colunas chaves de repetem
options.getGroupByFunctions().put(sumColumnID, CSVGroupByFunction.SUM);
|
Deste modo teremos apenas 1 linha com cada valor distinto das colunas definidas como chave, e os valores da coluna 'sumColumnID' serão somados.
O CSVGenerator também suporta outras funções como 'MIN' (Valor Mínimo), 'MAX (Valor Máximo), etc. Consulte o JavaDoc dos elementos da enum CSVGroupByFunction para mais detalhes sobre as funções.