• Java 将对象List转为csv文件并上传远程文件服务器实现方案


    问题情景:

    最近项目中遇到了根据第三方系统传递过来的参数,封装为List<实体类对象>后,将该实体类转换为csv文件,然后上传到远程的sftp服务器指定目录的需求。

    实现思路:

    1. List<实体类对象>转为csv文件的过程。通过OpenCsv实现。

    阻塞点:

    1.最开始遇到了生成的csv文件的第一行生成的字段名,变成了实体类的大写字段名了,例如userName变为USERNAME并且排序混乱。
    2.通过查阅资料找到了以下两个注解,后期却发现两个注解不能同时出现。详见文章
    为什么 opencsv 在写入文件时将 csv 标头大写

    @CsvBindByName(column = "TradeID")
    @CsvBindByPosition(position = 0)
    
    • 1
    • 2

    解决方案:

    方案一:
    创建自定义MappingStrategy :

    class CustomMappingStrategy extends ColumnPositionMappingStrategy {
    private static final String[] HEADER = new String[]{“TradeID”, “GWML GUID”, “MXML GUID”, “GWML File”, “MxML File”, “MxML Counterparty”, “GWML Counterparty”};

    @Override
    public String[] generateHeader() {
        return HEADER;
    }
    
    • 1
    • 2
    • 3
    • 4

    }
    并在StatefulBeanToCsvBuilder使用它:

    final CustomMappingStrategy mappingStrategy = new CustomMappingStrategy<>();
    mappingStrategy.setType(MappingsBean.class);

    final StatefulBeanToCsv beanToCsv = new StatefulBeanToCsvBuilder(writer)
    .withMappingStrategy(mappingStrategy)
    .build();
    beanToCsv.write(makeFinalMappingBeanList());
    writer.close()
    在MappingsBean类中,我们留下了CsvBindByPosition注释 - 以控制排序(在此解决方案中, CsvBindByName注释)。 由于自定义映射策略,标题列名称包含在生成的 CSV 文件中。

    此解决方案的缺点是,当我们通过CsvBindByPosition注释更改列顺序时,我们必须手动更改自定义映射策略中的HEADER常量。

    方案二:
    该方案可以根据实体类字段名称生成CSV第一行,注意一定不要加@CsvBindByName注解,具体文章可以参考opencsv 将对象数组导出为 csv 文件时、文件列按对象字段定义顺序排序的实现

    @SneakyThrows
    public  String generateCsvFile(List exportResults, String fileName)
            throws IOException, CsvDataTypeMismatchException, CsvRequiredFieldEmptyException {
        String finalFileName = new File(nginxDownloadPath,
                fileName + System.currentTimeMillis() + ".csv").getPath();
        Writer writer = new FileWriter(finalFileName);
        CSVWriter csvWriter = new CSVWriter(
                writer,
                CSVWriter.DEFAULT_SEPARATOR,
                CSVWriter.DEFAULT_QUOTE_CHARACTER,
                CSVWriter.NO_ESCAPE_CHARACTER,
                CSVWriter.DEFAULT_LINE_END);
                csvWriter.writeNext(header);
        if (exportResults.size() > 0) {
            //写内容
            StatefulBeanToCsv beanToCsv = new StatefulBeanToCsvBuilder(writer).
                    withMappingStrategy(new OrderColumnMappingStrategy(exportResults.get(0).getClass())).
                    withIgnoreField(exportResults.get(0).getClass(), Arrays.stream(exportResults.get(0).getClass().getDeclaredFields()).filter(one -> {
                        one.setAccessible(true);
                        return one.isAnnotationPresent(CsvIgnore.class);
                    }).findFirst().orElse(null)).
                    build();
            beanToCsv.write(exportResults);
        }
        csvWriter.close();
        writer.close();
        return finalFileName;
    }
    
    public class OrderColumnMappingStrategy extends HeaderColumnNameMappingStrategy {
        private Locale errorLocale = Locale.getDefault();
    
        public OrderColumnMappingStrategy(Class type) {
            super();
            this.setErrorLocale(errorLocale);
            this.setType(type);
        }
    
        @Override
        public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {
            if (type == null) {
                throw new IllegalStateException(ResourceBundle
                        .getBundle(ICSVParser.DEFAULT_BUNDLE_NAME, errorLocale)
                        .getString("type.before.header"));
            }
    
            if (headerIndex.isEmpty()) {
                List realHeaderList = new ArrayList<>();
    			/**getFieldNameForCsvHeader()方法是通过反射获取对象的字段, 字段
    			是按照定义顺序返回的. 这里就不贴出代码了*/
                getFieldNameForCsvHeader(type).forEach(one -> {
                    realHeaderList.add(one.toUpperCase());
                });
                String[] header = realHeaderList.toArray(new String[0]);
                headerIndex.initializeHeaderIndex(header);
                return header;
            }
            return headerIndex.getHeaderIndex();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
  • 相关阅读:
    算法整理(二)
    FFmpeg进阶: 音频滤镜大全
    小迪安全37WEB 攻防-通用漏洞&XSS 跨站&权限维持&钓鱼捆绑&浏览器漏洞
    Flutter macOS开发教程之 界面布局与UI组件源码(教程含源码)
    Java关系运算符简介说明
    Linux应用之OTA升级
    Kafka消费异常报Failing OffsetCommit request since the consumer
    机器学习:探寻智能化时代的科技奇迹
    《明解C语言》第三版 (入门篇) 第五章练习答案
    【云原生 • Kubernetes】kubernetes 核心技术 - Pod
  • 原文地址:https://blog.csdn.net/qq_40303219/article/details/134079380