• Java注解(二):实战 - 直接使用对象列表生成报表


    通过对Java注解(一):介绍,思想及优点学习了解,相信大家对Java注解有一定程度的了解,本篇文章将实战项目中的应用来加深对Java注解的了解。

    本实例实现根据指定字段的JavaBean,生成对应列的报表。使用Java注解就是方便实现JavaBean与Excel或CSV列已一一映射。直观展现数据,不需要中间转换,Java注解可以很轻松实现。

    下面先给出Java注解的定义:

    import java.lang.annotation.*;
    
    /**
     * 类功能描述:列属性
     *
     * @author WangXueXing create at 18-10-29 下午4:40
     * @version 1.0.0
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    public @interface ColumnProperty {
        /**
         * 列序号
         * @return
         */
        int index();
    
        /**
         * 列表头名
         * @return
         */
        String name();
    }
    

      本注解定义目的是使用在JavaBean的每个字段映射到Excel中的列序号及列表头名。这样对于开发者,我只需要定义好报表展示的列及相对位置,并组装JavaBean list.直观,不需要关心转换过程。

    下面代码就是定义JavaBean及使用上面定义的注解:

    import com.today.service.financereport.util.ColumnProperty
    
    import scala.annotation.meta.field
    import scala.beans.BeanProperty
    
    /**
      * 类功能描述:营收明细
      *
      * @author WangXueXing create at 18-10-23 下午7:52
      * @version 1.0.0
      */
    case class IncomeDetail(/** 店号		 */
                            @(ColumnProperty@field)(index = 0, name = "店号")
                            @BeanProperty
                            storeId: String,
    
                            /** 店名		 */
                            @(ColumnProperty@field)(index = 1, name = "店名")
                            @BeanProperty
                            storeName: String,
    
                            /** 门店类型		 */
                            @(ColumnProperty@field)(index = 2, name = "门店类型")
                            @BeanProperty
                            storeType: String,
    
                            /** 营业日期		 */
                            @(ColumnProperty@field)(index = 3, name = "营业日期")
                            @BeanProperty
                            businessDate: String,
    
                            /** 交易时间		 */
                            @(ColumnProperty@field)(index = 4, name = "交易时间")
                            @BeanProperty
                            payTime: String,
    
                            /** 订单号		 */
                            @(ColumnProperty@field)(index = 5, name = "订单号")
                            @BeanProperty
                            orderNo: String,
    
                            /** 交易流水号		 */
                            @(ColumnProperty@field)(index = 6, name = "交易流水号")
                            @BeanProperty
                            tradeNo: String,
    
                            /** 金额		 */
                            @(ColumnProperty@field)(index = 7, name = "金额")
                            @BeanProperty
                            tradeAmount: BigDecimal,
    
                            /** 抹零金额		 */
                            @(ColumnProperty@field)(index = 8, name = "抹零金额")
                            @BeanProperty
                            spotAmount: BigDecimal,
    
                            /** 支付方式		 */
                            @(ColumnProperty@field)(index = 9, name = "支付方式")
                            @BeanProperty
                            tradeType: String,
    
                            /** POS机		 */
                            @(ColumnProperty@field)(index = 10, name = "POS机")
                            @BeanProperty
                            posId: String,
    
                            /** 收银员		 */
                            @(ColumnProperty@field)(index = 11, name = "收银员")
                            @BeanProperty
                            cashierName: String,
    
                            /** 订单类型  */
                            @(ColumnProperty@field)(index = 12, name = "订单类型")
                            @BeanProperty
                            payType: String,
    
                            /** 第三方商户订单号  */
                            @(ColumnProperty@field)(index = 13, name = "第三方商户订单号")
                            @BeanProperty
                            thirdPartyPaymentNo: String
                           )
    

      其中@BeanProperty是Scala自带的一个注解,就是免去Java中对每个字段的getter()与setter()的定义。

     以下是伪代码,从数据库中获取对应数据结构为IncomeDetail的数据列表:

    def getReportData: List[IncomeDetail] = {
        return jdbc.getIncomeDetailList()
    }
    

      获取到数据后,将数据通过注解转换并填入报表:

    val incomeDetailList = getReportData()
    val file = File.createTempFile( "营收明细报表_" + MathUtils.getRandom(4), ".csv")
          ScalaFunction.tryWithResources(new PrintWriter(file, "GBK")) { out =>
            val dataObj =incomeDetailList.isInstanceOf[Seq[AnyRef@unchecked]] match {
              case true => incomeDetailList.asInstanceOf[List[AnyRef@unchecked]]
              case _ => List.empty
            }
            //根据注解顺序生成CSV数据列表
            AnnotationUtil.getValueWithHead(dataObj).foreach(out.println(_))
          }
    

      其中ScalaFunction.tryWithResources()仿照Java try with resources本人定义了一个Scala函数来处理流关闭,详情请参考我以前的博客:Scala实现Try with resources自动关闭IO

    /**
      * 类功能描述:Scala高级函数
      *
      * @author WangXueXing create at 18-11-22 下午5:29
      * @version 1.0.0
      */
    object ScalaFunction {
      /**
        * Scala实现Java7 try-with-resources
        * @see https://www.cnblogs.com/barrywxx/p/10002422.html
        */
      def tryWithResources[A <: {def close(): Unit }, B](a: A)(f: A => B): B = {
        try {
          f(a)
        } finally {
          if(a != null){
            a.close()
          }
        }
      }
    }
    

      我们重点关注下AnnotationUtil.getValueWithHead(), 这个方法定义了通过注解将数据填入Excel或CSV报表的过程:

    import java.lang.reflect.Field
    
    import com.today.service.financereport.dto.IncomeDetail
    
    /**
      * 类功能描述:Scala注解工具类
      *
      * @author WangXueXing create at 18-10-30 下午3:35
      * @version 1.0.0
      */
    object AnnotationUtil {
      /**
        * 根据注解获取值列表
        */
      def getValueWithHead(valList: List[_]): List[String] ={
        var fields: Array[Field] = Array.empty
        val dataList: List[String] = valList.zipWithIndex.map{ x=>
          if(x._2 == 0){
            fields = x._1.getClass.getDeclaredFields.sortBy(_.getAnnotations.apply(0).asInstanceOf[ColumnProperty].index())
          }
    
          fields.map{f=>
             f.setAccessible(true)
             val value = f.get(x._1)
             if(value == null){
                ""
             } else {
               value.toString
             }
          }.mkString(",")
        }
        fields.map(_.getAnnotation(classOf[ColumnProperty]).name()).mkString(",")+:dataList
      }
    
      def main(args: Array[String]): Unit = {
        val list = List(IncomeDetail("wew1","eerr1","wrw1",null,"1","1","1",BigDecimal(12.1),BigDecimal(12.1),"1","1","1"),
                        IncomeDetail("rer2","wrwrw2","wrw2","2","2","2","2",BigDecimal(12.1),BigDecimal(12.1),"2","2","2"))
    
        val objList = getValueWithHead(list)
        objList.foreach(println(_))
      }
    }
    

      好了,到这里,这个实例已经完成。是不是以后就不需要关注怎样组装复杂报表数据结构,只需要将JavaBean定义好,按照这个JavaBean的数据结构组装数据就行了!

  • 相关阅读:
    Android仿人人客户端(v5.7.1)——个人主页(三)
    hdu2554-N对数的排列问题
    POJ1363:Rails
    golang printf
    HDU1200:To and Fro
    [C# 基础知识系列]专题六:泛型基础篇——为什么引入泛型
    poj 2480 (欧拉函数应用)
    Re:从0开始的微服务架构--(二)快速快速体验微服务架构?--转
    爬虫推荐的工具
    python2 与 python3 语法区别--转
  • 原文地址:https://www.cnblogs.com/barrywxx/p/10284843.html
Copyright © 2020-2023  润新知