JavaBean转换为Csv

在开发中我们经常遇到导出csv文件的需求,而数据是一个List,list里面是JavaBean对象。
下面是一个简单的示例

 StringBuilder header = new StringBuilder();
 header.append(" 媒体ID,广告消耗(元),备注\n");
 for (SettledMonthReportRsp data : datas) {
    StringBuilder row = new StringBuilder();
    row.append(START_PREFIX);
    //普通的数据
    row.append(data.getAppId());
    row.append(WORD_SEPARATOR);
    //为保存金额的准确,数据库用整数,前台转成小数
    row.append(DataTool.calculateFenToYuan(data.getAdvertConsume()));
    row.append(WORD_SEPARATOR);
    //有些需求我们在没有值时不显示null,需要特殊处理
    row.append(ObjectUtils.defaultIfNull(data.getNote(),"-"));
    row.append(END_POSTFIX);
    header.append(row);
}
  1. 标题和内容没有对应起来,一不留神就会对应错字段
  2. 代码不直观,有很多模板代码

然后希望使用csv的库来简化代码,然后就选择了uniVocity-parsers 这个库,戳这里访问github地址。


1. 项目中引入uniVocity-parsers依赖
2. 使用

CsvWriterSettings settings = new CsvWriterSettings();
//这里需要设置处理的类型,就是JavaBean的类型
BeanWriterProcessor beanWriterProcessor = new BeanWriterProcessor<>(classType);
settings.setRowWriterProcessor(beanWriterProcessor);
//设置编码及输出
CsvWriter writer = new CsvWriter(out, Charset.forName("GBK"), settings);
//写标题
writer.writeHeaders();
//写内容
targetList.forEach(writer::processRecord);
writer.close();
  1. 上面的代码只需要换掉classType即可,你可能会好奇业务逻辑在哪里处理,实际上业务逻辑基本上都在JavaBean中(下面的代码和一开始的例子没有任何关系)。
public class SlotDataRsp {

    @Parsed(field = "媒体ID")
    private Long   appId;

    @Parsed(field = "广告位曝光", defaultNullWrite = "-")
    private Long   actExposeCount;

    @Convert(conversionClass = PercentConversion.class)
    @Parsed(field = "广告位点击率", defaultNullWrite = "-")
    private Float  actClickRate;

    @Convert(conversionClass = FenToYuanConversion.class)
    @Parsed(field = "广告消耗(元)", defaultNullWrite = "-")
    private Long   adConsume;

//省略setter和getter方法
}

下面解释一下上面的JavaBean:
@Parsed(field = "广告消耗(元)", defaultNullWrite = "-")中field代表此字段对应的标题名称,defaultNullWrite代表此字段为null时该如何显示,这里需要注意的是,这里是使用get方法返回的值为null。

public String getActClickRate() {
    return actClickRate+"%";
}

比如上面的get方法当launchSuccessRate为null是并不会为-,因为框架会判断返回为-,并不为null,当然我们也可以用这个特性做一些定制。

@Parsed还可以使用一个参数index,可以定义标题的顺序,从1开始。如果不定义,如上面的JavaBean,他会按照字段声明的先后顺序,一遍还是建议定义index参数。我之所以不定义index的原因在于,我有另一JavaBean继承了这个类,我需要在这个类的首位再添加一个当前日期的标题,如果定义了index,子类的字段只能在父类的后面了。

上面的actClickRate+"%"中我需要将一个浮点型转成一个百分比,只要在后面加一个百分号即可,一开始我是使用上面的那种方法。上面那种方法维护性并不好,于是又找了一下,我发现我们可以实现Conversion类来自定义转换。

public class PercentConversion implements Conversion<String,String> {

    //csv转JavaBean使用
    @Override public String execute(String input) {
        return null;
    }

    //导出使用
    @Override public String revert(String input) {
        if(NumberUtils.isNumeric(input)) {
            return input + "%";
        }else {
            return input;
        }
    }
}

然后我就可以使用 @Convert(conversionClass = PercentConversion.class)注解,这样逻辑就非常明了而且非常利于复用。上述代码当然也并不完美,我知道input肯定是一个数字,但是我将Conversion<String,String>修改为Conversion<String,Long>导出时会出错。

for (int i = conversions.size() - 1; i >= 0; i--) {
    conversion = conversions.get(i);
    value = conversion.revert(value);
}

我们看到conversions.size,它先会用默认的转换成String,然后在调用你的自定义转换。所以我只能实现Conversion<String,String>,目前也没有找到其他办法。

如果你仔细想了,为什么不直接返回return input + "%",我们需要关心其是不是数字,我们只要在其后拼上百分号即可。问题在于他会和@Parsed(field = "广告位点击率", defaultNullWrite = "-")中的defaultNullWrite有冲突,如果input为null,则会返回null%,这样不会显示-。

对于上面的代码,我们还可以进一步封装:

public static <T, U> void export(OutputStream out, List<T> sourceList, Class<U> classType) {
    List<U> targetList = new ArrayList<>();
    CsvWriterSettings settings = new CsvWriterSettings();

    BeanWriterProcessor beanWriterProcessor = new BeanWriterProcessor<>(classType);
    settings.setRowWriterProcessor(beanWriterProcessor);
    CsvWriter writer = new CsvWriter(out, Charset.forName("GBK"), settings);
    writer.writeHeaders();
    if(sourceList==null){
        writer.close();
        return;
    }

    try {
        for (T t : sourceList) {
            U u = classType.newInstance();
            BeanUtils.copyProperties(t, u);
            targetList.add(u);
        }
    } catch (Exception e) {
        throw new ExportException(ErrorCode.E9999999);
    }
    targetList.forEach(writer::processRecord);
    writer.close();
}

我们使用的时候就可以像这样

if(req.getExportType()==0){
    ExportTool.export(out, slotStatisticsDataList, SlotDataRsp.class);
}else {
    ExportTool.export(out, slotStatisticsDataList, SlotDailyDataRsp.class);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值