通过对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的数据结构组装数据就行了!

Java注解(二):实战 - 直接使用对象列表生成报表的更多相关文章

  1. java实现二维码的生成.

    目录 1.二维码概念  2.二维码发展历史  3.二维码分类  4.二维码优缺点  5.QR Code  1.二维码又称  二维条码 (2-dimensional bar code)是用某种特定的几何 ...

  2. 分享知识-快乐自己:全面解析 java注解实战指南

    请你在看这篇文章时,不要感到枯燥,从头到尾一行行看,代码一行行读,你一定会有所收获的. 问: 为什么学习注解? 学习注解有什么好处? 学完能做什么? 答: 1):能够读懂别人的代码,特别是框架相关的代 ...

  3. java实现二维码的生成与解析

    简单介绍下二维码:二维码其实就是一种编码技术,只是这种编码技术是用在图片上了,将给定的一些文字,数字转换为一张经过特定编码的图片,而解析二维码则相反,就是将一张经过编码的图片解析为数字或者文字. 当然 ...

  4. Java JDBC学习实战(二): 管理结果集

    在我的上一篇博客<Java JDBC学习实战(一): JDBC的基本操作>中,简要介绍了jdbc开发的基本流程,并详细介绍了Statement和PreparedStatement的使用:利 ...

  5. java版gRPC实战之二:服务发布和调用

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  6. 【Java并发编程实战】----- AQS(二):获取锁、释放锁

    上篇博客稍微介绍了一下AQS,下面我们来关注下AQS的所获取和锁释放. AQS锁获取 AQS包含如下几个方法: acquire(int arg):以独占模式获取对象,忽略中断. acquireInte ...

  7. java实现二维码生成的几个方法

    1: 使用SwetakeQRCode在Java项目中生成二维码 http://swetake.com/qr/ 下载地址 或着http://sourceforge.jp/projects/qrcode/ ...

  8. Java条形码/二维码生成和解析

    注意-本类依赖jar包文件:core.jar和zxing-javase.jar 下载jar文件,到本博客文件栏目下载. import com.google.zxing.BarcodeFormat; i ...

  9. java注解之二

    从JDK5开始,Java增加了Annotation(注解),Annotation是代码里的特殊标记,这些标记可以在编译.类加载.运行时被读取,并执行相应的处理.通过使用Annotation,开发人员可 ...

随机推荐

  1. echarts实现中国地图数据展示

    在项目中运用到图形展示数据太常见了,echarts是一款使用率非常高的插件工具,很多大平台都是使用echarts: 一般运用到条形.折线.扇形图,今天说一说在中国地图上展示各地数据: 首先要准备中国地 ...

  2. C#更改操作系统时间

    using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServi ...

  3. UE4学习心得:Scene Component蓝图的一个简单应用

    Scene Component是蓝图类中一个不怎么常用的分类(特别是对于新手而言),主要是其实现的功能可以在Actor类中用相同的方法实现,使其作用显得有点多余. 笔者在使用过这个类之后发现其作用更相 ...

  4. var与let、const的区别

    var与let.const 一.var声明的变量会挂载在window上,而let和const声明的变量不会: var a = 100;console.log(a,window.a); // 100 1 ...

  5. webpack4 splitChunksPlugin && runtimeChunkPlugin 配置杂记

    webpack2 还没研究好,就发现升级到4了,你咋这么快~ 最近要做项目脚手架,项目构建准备重新做,因为之前写的太烂了...然后发现webpack大版本已经升到4了(又去看了一眼,4.5了),这么快 ...

  6. 第七章之S5PV210移植到Nandflash

    1,之前的操作都是基于SD卡进行运行的,如今在Nandfalsh中运行u-boot.因为s5p_goni.h配置文件没有配置Nand相关文件,所以先配置Nand文件. 在include/configs ...

  7. PAT1006:Sign In and Sign Out

    1006. Sign In and Sign Out (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue ...

  8. 使用libpcap获取http报文

    在上一篇博客中简单对libpcap库基本函数及基本工作流程做了些简单说明, 今天我们先了解一下pcap_loop()及pcap_dispatch()函数的功能及作用: (1)pcap_loop()循环 ...

  9. SSM-SpringMVC-10:SpringMVC中PropertiesMethodNameResolver属性方法名称解析器

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 上次的以继承MultiActionController可以实现一个处理器中多个处理方法,但是局限出来了,他们的 ...

  10. .Net中集合排序的一种高级玩法

    背景: 学生有名称.学号, 班级有班级名称.班级序号 学校有学校名称.学校编号(序号) 需求 现在需要对学生进行排序 第一排序逻辑 按学校编号(序号)排列 再按班级序号排列 再按学生学号排列 当然,在 ...