- ?
Python——一个简单的自动化测试框架
友卉
展开
这是柠檬班的第171篇文章
最近办公室的开发哥哥,每天都嚣张的很,说让我弄死他。于是我本着善良助人的天性,来学习接口自动化,并准备在他快下班的时候,给他多提几十个bug。嗯,就是这样,对的,没错
开始接口自动化首先,我们要选择一门语言,测试人员的标配,当然是Python3,不要问为什么,简单粗暴,上手快没有基础的同学可以先去学习一下python基础。首推菜鸟教程和廖雪峰接下来我们看一下我们的接口自动化框架的主要构成。嘿嘿嘿
接口自动化框架一共分为6个模块common:公共模块,包括配置和共用的代码source:接口封装的类test_case:存放单元测试用例test_data:存放测试数据(这里用的是Excel)test_report:存放测试报告的地址test_result:存放测试结果的地址
公共类首先开始编写我们的公共类
HTTP类这里封装了2个函数,一个get请求,一个post请求,并以data形式返回测试结果
读取配置文件的类其实就是为了把什么固定的ip地址,端口,数据库连接信息啦放在配置文件里面,并通过类读取调用,实现数据分离,更加灵活
读取Excel的类将测试数据放在Excel中,通过Excel进行数据管理,如下图
存放测试数据然后通过Excel类读取调用,这些就实现了Excel管理测试用例,然后想测什么接口,就直接在Excel里面加就行。想想都爽,成功的走向了,弄死同事的第一步。
这是我们的核心代码
将测试结果写入Excel,并生成HTML测试报告发送到邮箱,这样,我们就可以坐在靠椅上,喝着咖啡,看着代码,然后等着邮件,最后再提上一大堆bug,嗯,大概生活就是如此的美好
最后让我们来执行我们的main函数对,没错,真相只有一个。见证奇迹的时候到了,然后就会生成我们想要的测试报告和测试结果
主函数入口
执行main的日志测试报告呐,一个崭新的测试报告就这么出来了,惊不惊喜,意不意外。就这样我们一起走向弄死同事的不归路。(ps:其实我们还是很相亲相爱的,当然,是他死我活)
测试报告下次有时间会再聊上五毛钱的基于Jenkins持续集成自动化的实践,当然这都是自己瞎捣鼓的,有大神的,请留言,一起共同进步。
- ?
「教程」终于有人把Java内存模型说清楚了!
喻夏岚
展开
网上有很多关于 Java 内存模型的文章,但是很多人读完之后还是搞不清楚,甚至有的人说自己更懵了。
本文就来整体的介绍一下 Java 内存模型,读完本文以后,你就知道到底 Java 内存模型是什么,为什么要有 Java 内存模型,Java 内存模型解决了什么问题等。
本文中很多说法都是笔者自己理解后定义出来的。希望能够让读者可以对 Java 内存模型有更加清晰的认识。
为什么要有内存模型
在介绍 Java 内存模型之前,我们先来看一下到底什么是计算机内存模型,然后再来看 Java 内存模型在计算机内存模型的基础上都做了哪些事情。
要说计算机的内存模型,就要说一段古老的历史,看一下为什么要有内存模型。
内存模型:英文名 Memory Model,它是一个老古董了。它是与计算机硬件有关的一个概念。那么,我先介绍下它和硬件到底有啥关系。
CPU 和缓存一致性
我们应该知道,计算机在执行程序的时候,每条指令都是在 CPU 中执行的,而执行的时候,又免不了和数据打交道。
而计算机上面的数据,是存放在主存当中的,也就是计算机的物理内存。
刚开始,还相安无事,但是随着 CPU 技术的发展,CPU 的执行速度越来越快。
而由于内存的技术并没有太大的变化,所以从内存中读取和写入数据的过程和 CPU 的执行速度比起来差距就会越来越大,这就导致 CPU 每次操作内存都要耗费很多等待时间。
这就像一家创业公司,刚开始,创始人和员工之间工作关系其乐融融,但是随着创始人的能力和野心越来越大,逐渐和员工之间出现了差距,普通员工越来越跟不上 CEO 的脚步。
老板的每一个命令,传达到基层员工之后,由于基层员工的理解能力、执行能力的欠缺,就会耗费很多时间。这也就无形中拖慢了整家公司的工作效率。
可是,不能因为内存的读写速度慢,就不发展 CPU 技术了吧?总不能让内存成为计算机处理的瓶颈吧?
所以,人们想出来了一个好的办法,就是在 CPU 和内存之间增加高速缓存。
缓存的概念大家都知道,就是保存一份数据拷贝。它的特点是速度快,内存小,并且价格昂贵。
那么,程序的执行过程就变成了:程序在运行过程中,会将运算需要的数据从主存复制一份到 CPU 的高速缓存当中。
那么 CPU 进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数据刷新到主存当中。
之后,这家公司开始设立中层管理人员,管理人员直接归 CEO 领导,领导有什么指示,直接告诉管理人员,然后就可以去做自己的事情了。管理人员负责去协调底层员工的工作。
因为管理人员是了解手下的人员以及自己负责的事情的。所以大多数时候,公司的各种决策,通知等,CEO 只要和管理人员之间沟通就够了。
而随着 CPU 能力的不断提升,一层缓存就慢慢的无法满足要求了,就逐渐的衍生出多级缓存。
按照数据读取顺序和与 CPU 结合的紧密程度,CPU 缓存可以分为一级缓存(L1),二级缓存(L2),部分高端 CPU 还具有三级缓存(L3),每一级缓存中所储存的全部数据都是下一级缓存的一部分。
这三种缓存的技术难度和制造成本是相对递减的,所以其容量也是相对递增的。
那么,在有了多级缓存之后,程序的执行就变成了:当 CPU 要读取一个数据时,首先从一级缓存中查找,如果没有找到再从二级缓存中查找,如果还是没有就从三级缓存或内存中查找。
随着公司越来越大,老板要管的事情越来越多,公司的管理部门开始改革,开始出现高层,中层,底层等管理者。一级一级之间逐层管理。
单核 CPU 只含有一套 L1,L2,L3 缓存;如果 CPU 含有多个核心,即多核 CPU,则每个核心都含有一套 L1(甚至和 L2)缓存,而共享 L3(或者和 L2)缓存。
公司也分很多种,有些公司只有一个大 Boss,他一个人说了算。但是有些公司有比如联席总经理、合伙人等机制。
单核 CPU 就像一家公司只有一个老板,所有命令都来自于他,那么就只需要一套管理班底就够了。
多核 CPU 就像一家公司是由多个合伙人共同创办的,那么,就需要给每个合伙人都设立一套供自己直接领导的高层管理人员,多个合伙人共享使用的是公司的底层员工。
还有的公司,不断壮大,开始拆分出各个子公司。各个子公司就是多个 CPU 了,互相之前没有共用的资源。互不影响。
下图为一个单 CPU 双核的缓存结构:
随着计算机能力不断提升,开始支持多线程。那么问题就来了,我们分别来分析下单线程、多线程在单核 CPU、多核 CPU 中的影响。
单线程:CPU 核心的缓存只被一个线程访问。缓存独占,不会出现访问冲突等问题。
单核 CPU,多线程:进程中的多个线程会同时访问进程中的共享数据,CPU 将某块内存加载到缓存后,不同线程在访问相同的物理地址的时候,都会映射到相同的缓存位置,这样即使发生线程的切换,缓存仍然不会失效。
但由于任何时刻只能有一个线程在执行,因此不会出现缓存访问冲突。
多核 CPU,多线程:每个核都至少有一个 L1 缓存。多个线程访问进程中的某个共享内存,且这多个线程分别在不同的核心上执行,则每个核心都会在各自的 Cache 中保留一份共享内存的缓冲。
由于多核是可以并行的,可能会出现多个线程同时写各自的缓存的情况,而各自的 Cache 之间的数据就有可能不同。
在 CPU 和主存之间增加缓存,在多线程场景下就可能存在缓存一致性问题,也就是说,在多核 CPU 中,每个核的自己的缓存中,关于同一个数据的缓存内容可能不一致。
如果这家公司的命令都是串行下发的话,那么就没有任何问题。
如果这家公司的命令都是并行下发的话,并且这些命令都是由同一个 CEO 下发的,这种机制是也没有什么问题。因为他的命令执行者只有一套管理体系。
如果这家公司的命令都是并行下发的话,并且这些命令是由多个合伙人下发的,这就有问题了。
因为每个合伙人只会把命令下达给自己直属的管理人员,而多个管理人员管理的底层员工可能是公用的。
比如,合伙人 1 要辞退员工 a,合伙人 2 要给员工 a 升职,升职后的话他再被辞退需要多个合伙人开会决议。两个合伙人分别把命令下发给了自己的管理人员。
合伙人 1 命令下达后,管理人员 a 在辞退了员工后,他就知道这个员工被开除了。
而合伙人 2 的管理人员 2 这时候在没得到消息之前,还认为员工 a 是在职的,他就欣然的接收了合伙人给他的升职 a 的命令。
处理器优化和指令重排
上面提到在 CPU 和主存之间增加缓存,在多线程场景下会存在缓存一致性问题。
除了这种情况,还有一种硬件问题也比较重要。那就是为了使处理器内部的运算单元能够被充分利用,处理器可能会对输入代码进行乱序执行处理。这就是处理器优化。
除了现在很多流行的处理器会对代码进行优化乱序处理,很多编程语言的编译器也会有类似的优化,比如 Java 虚拟机的即时编译器(JIT)也会做指令重排。
可想而知,如果任由处理器优化和编译器对指令重排的话,就可能导致各种各样的问题。
关于员工组织调整的情况,如果允许人事部在接到多个命令后进行随意拆分乱序执行或者重排的话,那么对于这个员工以及这家公司的影响是非常大的。
并发编程的问题
前面说的和硬件有关的概念你可能听得有点蒙,还不知道他到底和软件有啥关系。
但是关于并发编程的问题你应该有所了解了,比如原子性问题,可见性问题和有序性问题。
其实,原子性问题,可见性问题和有序性问题是人们抽象定义出来的。而这个抽象的底层问题就是前面提到的缓存一致性问题、处理器优化问题和指令重排问题等。
这里简单回顾下这三个问题,我们说,并发编程,为了保证数据的安全,需要满足以下三个特性:
原子性,是指在一个操作中,CPU 不可以在中途暂停然后再调度,即不被中断操作,要不执行完成,要不就不执行。可见性,是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。有序性,即程序执行的顺序按照代码的先后顺序执行。
有没有发现,缓存一致性问题其实就是可见性问题。而处理器优化是可以导致原子性问题的。指令重排即会导致有序性问题。
所以,后文将不再提起硬件层面的那些概念,而是直接使用大家熟悉的原子性、可见性和有序性。
什么是内存模型
前面提到的,缓存一致性问题、处理器优化的指令重排问题是硬件的不断升级导致的。那么,有没有什么机制可以很好的解决上面的这些问题呢?
最简单直接的做法就是废除处理器和处理器的优化技术、废除 CPU 缓存,让 CPU 直接和主存交互。
但是,这么做虽然可以保证多线程下的并发问题。但是,这就有点因噎废食了。
所以,为了保证并发编程中可以满足原子性、可见性及有序性。有一个重要的概念,那就是——内存模型。
为了保证共享内存的正确性(可见性、有序性、原子性),内存模型定义了共享内存系统中多线程程序读写操作行为的规范。
通过这些规则来规范对内存的读写操作,从而保证指令执行的正确性。它与处理器有关、与缓存有关、与并发有关、与编译器也有关。
它解决了 CPU 多级缓存、处理器优化、指令重排等导致的内存访问问题,保证了并发场景下的一致性、原子性和有序性。
内存模型解决并发问题主要采用两种方式:
限制处理器优化使用内存屏障
本文就不深入底层原理来展开介绍了,感兴趣的朋友可以自行学习。
什么是 Java 内存模型
前面介绍了计算机内存模型,这是解决多线程场景下并发问题的一个重要规范。
那么具体的实现是如何的呢?不同的编程语言,在实现上可能有所不同。
我们知道,Java 程序是需要运行在 Java 虚拟机上面的,Java 内存模型(Java Memory Model,JMM)就是一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,保证了 Java 程序在各种平台下对内存的访问都能保证效果一致的机制及规范。
提到 Java 内存模型,一般指的是 JDK 5 开始使用的新内存模型,主要由 JSR-133:JavaTM Memory Model and Thread Specification 描述。
感兴趣的可以参看下这份PDF文档:
http://cs.umd.edu/~pugh/java/memoryModel/jsr133.pdf
Java 内存模型规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存。
线程的工作内存中保存了该线程中用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。
不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量的传递均需要自己的工作内存和主存之间进行数据同步进行。
而 JMM 就作用于工作内存和主存之间数据同步过程。它规定了如何做数据同步以及什么时候做数据同步。
这里面提到的主内存和工作内存,读者可以简单的类比成计算机内存模型中的主存和缓存的概念。
特别需要注意的是,主内存和工作内存与 JVM 内存结构中的 Java 堆、栈、方法区等并不是同一个层次的内存划分,无法直接类比。
《深入理解Java虚拟机》中认为:如果一定要勉强对应起来的话,从变量、主内存、工作内存的定义来看,主内存主要对应于 Java 堆中的对象实例数据部分。而工作内存则对应于虚拟机栈中的部分区域。
所以,再来总结下,JMM 是一种规范,是解决由于多线程通过共享内存进行通信时,存在的本地内存数据不一致、编译器会对代码指令重排序、处理器会对代码乱序执行等带来的问题。
目的是保证并发编程场景中的原子性、可见性和有序性。
Java 内存模型的实现
了解 Java 多线程的朋友都知道,在 Java 中提供了一系列和并发处理相关的关键字,比如 Volatile、Synchronized、Final、Concurren 包等。
其实这些就是 Java 内存模型封装了底层的实现后提供给程序员使用的一些关键字。
在开发多线程的代码的时候,我们可以直接使用 Synchronized 等关键字来控制并发,这样就不需要关心底层的编译器优化、缓存一致性等问题。
所以,Java 内存模型,除了定义了一套规范,还提供了一系列原语,封装了底层实现后,供开发者直接使用。
我们前面提到,并发编程要解决原子性、有序性和一致性的问题。下面我们就再来看下,在 Java 中,分别使用什么方式来保证。
原子性
在 Java 中,为了保证原子性,提供了两个高级的字节码指令 Monitorenter 和 Monitorexit。
在 Synchronized 的实现原理文章中,介绍过,这两个字节码,在 Java 中对应的关键字就是 Synchronized。
因此,在 Java 中可以使用 Synchronized 来保证方法和代码块内的操作是原子性的。
可见性
Java 内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值的这种依赖主内存作为传递媒介的方式来实现的。
Java 中的 Volatile 关键字提供了一个...
- ?
不写代码不用 Excel, 如何轻松搞定各种图形化展现
台阶
展开
近期,大屏展示再次把 ”统计图” 推向热搜榜。或许你会问为什么,这多半是因为大屏通过各种图形组件集中呈现了用户关心的数据,而其中每个组件基本都是一个呈现形态各异的统计图,有的体现了某时间段某维度的数据走向,有的则是表示了某部分数据在整体的占比,亦或是分布聚集情况,凡此种种,不一而足。
相信资深的制表绘图师都知道,早期在报表工具还未普及时,想要实现各种统计结果的图形化呈现,基本都得通过代码或者 excel 来做,不仅开发费时费力,而且灵活性很差。
这里就以 Excel 为例,看一看具体的操作过程。假设某软件公司年中会议时要求销售主管向公司领导层汇报这半年各个产品不同维度(按产品线、按月、按销售经理等)的销售情况。
当销售主管得到这个通知后,往往需要做以下几步操作:
首先,通过各个销售经理获取每个人的销售明细数据,然后再使用 excel 透视表来完成针对这些数据的报表制作和数据分析工作,接下来再按照要求绘图。
这个过程看似简单,其实工作量非常庞大。我们细细回顾一下这个过程,可以看到从取数到制表绘图,难以避免以下这几个问题:
取数响应不够及时和灵活:一般销售人员常常奔波于全国各地,很多时候并不能及时将明细数据进行汇总整理,以至于销售主管很可能要等好几天才能拿到数据。需求沟通存在误差:销售主管最终拿到的数据结果可能并不是最初想要的,可能由于沟通表达导致存在一定的偏差。Excel 的局限:Excel 看似万能,但一旦数据量庞大,要写的函数多,真是挺影响效率的。而且在某些数据分析统计场景下,表现的不够丰富灵活,需要很多冗余操作。
那么有没有可能能够让销售经理能够在奔波的间隙,将销售数据及时的整理到销售部门的数据库中,然后由销售主管直接从数据库中读取数据进行数据分析、制表以及绘图,真正做到响应高效及时、制表绘图轻松愉快呢?
答案是肯定的,只要你拥有一款神器——润乾报表工具,上面所提到的或没提到的沟沟坎坎都能轻松搞定:
首先,我们可以应用该神器的填报功能,来保证销售数据的及时入库。其次,我们还可以通过简简单单的拖拖拽拽,来完成数据的分析制表。最后,我们还可以轻松愉快的完成绘图工作。
好了,话不多说,接下来我们直奔今天的主题,get 一下通过此神器可以做出哪些图形。
注:本文重点说明绘图部分,数据处理部分一带而过。
线图
以线条直观地呈现出某时期,不同部门 2 个产品的销售量差异。
饼图
以饼图直观地表现出某时段各个销售经理的销售额在整个部门的占比。
柱图
以柱子的高度用来比较两个或以上的生产值间的差异
甘特图
清楚地标识出某项目在不同时间段的完成情况。
地图
以地图为底本,用各种几何图形、实物形象或不同线纹、颜色等表明指标的大小及其分布状况,可以突出说明某些现象在地域上的分布、对某些现象进行不同地区间的比较,以及展示现象所处的地理位置及与其他自然条件的关系等
柱线图
集柱图与线图的优势于一身,下图中既可以以柱图的形式表现出同一时间蒸发量与降水量的差异,又可以以平滑的曲线呈现出一年的气温变化。
等等。
怎么样,是不是瞬间感觉在老板面前能加分不少?接下来,就让我们看看怎样不写代码不用 Excel, 轻松搞定各种图形化展现。
搭建数据桥梁 取数(新建数据源、数据集);
拖拖拽拽 搞定数据分析;
选择统计图类型,指定分类轴、系列轴、系列名称取值;
其中:
左侧参数部分为右侧 javaScript 代码的变量,一般包含 3 个变量分别是分类名称、系列值、系列名称;
右侧部分为图形的 javaScript 脚本,可引入第三方图形(比如:echarts,Highcharts)也可以点击打开模板使用自带的图形模板。
确定,保存。
到此为止,我们就可以不写代码不用 Excel, 轻松搞定一个统计图形了,最后的呈现结果如下:
最最后,悄悄告诉您,虽然我们已经为每个统计图提供了丰富的样式风格,但可能还是入不了您的法眼,不过没关系,您还可以完全自定义样式风格奥!!!
- ?
Java开发人员必知必会的20种常用类库和API
薛雅香
展开
一个有经验的Java开发人员特征之一就是善于使用已有的轮子来造车。《Effective Java》的作者Joshua Bloch曾经说过:“建议使用现有的API来开发,而不是重复造轮子”。在本文中,我将分享一些Java开发人员应该熟悉的最有用的和必要的库和API。顺便说一句,这里不包括框架,如Spring和Hibernate因为他们非常有名,都有特定的功能。
本文总结了日志、JSON解析、单测、XML解析、字节码处理、数据库连接池、集合类、邮件、加密、嵌入式SQL数据库、JDBC故障诊断以及序列化等20个方面的常用类库。都是你日常开发经常可能要用到的,现在不用不要紧,但是你要知道有这么一篇文章可以供你参考。
不知道不可怕,可怕的是你不知道你不知道。
一、日志相关类库
日志库是很常见的,因为你在每一个项目中都需要他们。打印日志是服务器端应用中最重要的事情,因为日志是你了解你的程序发生了什么的唯一途径。尽管JDK附带自己的日志库,但是还是有很多更好的选择可用,例如Log4j、SLF4j和LogBack。
Java开发人员应该熟悉日志记录的利弊,并且了解为什么SLF4J要比Log4J要好。
二、JSON解析库
在当今世界的web服务和物联网中(IoT),JSON已经取代了XML,成为从客户端到服务器传送信息的首选协议。有一个好消息和一个坏消息。坏消息是JDK没有提供JSON库。好消息是有许多优秀的第三方库可以用来解析和创建JSON消息,如Jackson 和 Gson
一个Java web开发人员应该熟悉Jackson 和 Gson这两种中的至少一种库。
三、单元测试库
单元测试技术的使用,是区分一个一般的开发者和好的开发者的重要指标。程序员经常有各种借口不写单元测试,但最常见的借口就是缺乏经验和知识。常见的单测框架有JUnit,Mockito和PowerMock。
四、通用类库
有几个很好的第三方通用库可供Java开发人员使用,例如Apache Commons和Google Guava。我会经常在我的代码中使用这些通用类库,因为这些类库都是经过无数开发者实践过的,无论是实用性还是在性能等方面都是最佳的。
五、Http 库
我不是很喜欢JDK的一个重要原因就包括他们缺乏对HTTP的支持。虽然可以使用java包类,但是这和直接使用像Apache HttpClient和HttpCore等开源类库比起来麻烦太多了。
尽管JDK 9将开始HTTP 2.0,也对HTTP的支持做了优化,但是我还是强烈建议所有的Java开发人员熟悉流行的HTTP处理类库,例如HttpClient和HttpCore HTTP等库。
六、XML解析库
市面上有很多XML解析的类库,如Xerces, JAXB, JAXP, Dom4j, Xstream等。Xerces2是下一代高性能,完全兼容的XML解析工具。Xerces2定义了 Xerces Native Interface (XNI)规范,并提供了一个完整、兼容标准的 XNI 规范实现。该解析器是完全重新设计和实现的,更简单以及模块化。
七、Excel读写库
许多应用程序需要提供把数据导出到Excel的功能,如果你要做相同的Java应用程序,那么你需要Apache POI API。
这是一个非常丰富的类库,你可以从Java程序读写XLS文件。
八、字节码库
如果你正在编写一个框架或者类库。有一些受欢迎的字节码库如javassist和Cglib Nodep可以供你选择,他们可以让你阅读和修改应用程序生成的字节码。
Javassist使得JAVA字节码操作非常简单。它是一个为编辑Java字节码而生的类库。ASM是另一个有用的字节码编辑库。
九、数据库连接池库
如果你的Java应用程序与数据库交互不是使用数据库连接池库的话,那么你就大错特错了。因为在运行时创建数据库连接非常耗时并且会拖慢你的程序。所以墙裂建议使用,有些好用的连接池可供选择,如Commons Pool 和 DBCP。
在web应用程序中,web服务器通常提供了这些功能。但是在java项目中需要把数据库连接池的类库导入到应用中。
十、消息传递库
像日志和数据库连接池一样,消息传递也是很多实际的Java项目中必备的。Java提供了JMS Java消息服务,但这不是JDK的一部分,你需要单独的引入jms.jar。类似地,如果您准备使用第三方消息传递协议,Tibco RV是个不错的选择。
十一、PDF处理库
除了Excel和Word,PDF也是一种常用的文件格式。如果你的应用程序要支持PDF格式的文件处理,你可以使用iText和Apache FOP类库。两者都提供了非常有用的PDF处理功能。
十二、日期和时间库
在Java之前,JDK的日期和时间库一直被人们所诟病,比如其非线程安全的、不可变的、容易出错等。很多开发人员会选择更好用的JodaTime类库。
但是在Java8推出之后,我们就可以彻底放弃JodaTime了,因为Java 8提供了其所有功能。但是,如果你的代码运行在一个低版本的JDK中,那么JodaTime还是值得使用的。
十三、集合类库
虽然JDK有丰富的集合类,但还是有很多第三方类库可以提供更多更好的功能。如Apache Commons Collections、 Goldman Sachs collections、 Google Collections和Trove。Trove尤其有用,因为它提供所有标准Collections 类的更快的版本以及能够直接在原语(primitive)(例如包含int 键或值的Map 等)上操作的Collections 类的功能。
FastUtil是另一个类似的API,它继承了Java Collection Framework,提供了数种特定类型的容器,包括映射map、集合set、列表list、优先级队列(prority queue),实现了java.util包的标准接口(还提供了标准类所没有的双向迭代器),还提供了很大的(64位)的array、set、list,以及快速、实用的二进制或文本文件的I/O操作类。
十四、邮件API
javax.mail 和 Apache Commons Email 提供了发送邮件的api。它们建立在JavaMail API的基础上,提供简化的用法。
十五、HTML解析库
和XML与JSON类似,HTML是另外一种我们可能要打交道的传输格式。值得庆幸的是,我们有jsoup可以大大简化Java应用程序使用HTML。你不仅可以使用JSoup解析HTML还可以创建HTML文档。
十六、加密库
Apache Commons家族中的Commons Codec就提供了一些公共的编解码实现,比如Base64, Hex, MD5,Phonetic and URLs等等。
十七、嵌入式SQL数据库库
我真的是非常喜欢像H2这种内存数据库,他可以嵌入到你的Java应用中。在你跑单测的时候如果你需要一个数据库,用来验证你的SQL的话,他是个很好的选择。顺便说一句,H2不是唯一嵌入式DB,你还有Apache Derby和HSQL可供选择。
十八、JDBC故障诊断库
有不错的JDBC扩展库的存在使得调试变得很容易,例如P6spy,这是一个针对数据库访问操作的动态监测框架,它使得数据库数据可无缝截取和操纵,而不必对现有应用程序的代码作任何修改。P6Spy 分发包包括P6Log,它是一个可记录任何 Java 应用程序的所有JDBC事务的应用程序。其配置完成使用时,可以进行数据访问性能的监测。
十九、序列化库
Google Protocol Buffer 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。
二十、网络库
一些有用的网络库主要有Netty的和Apache MINA。如果您正在编写一个应用程序,你需要做的底层网络任务,可以考虑使用这些库。
这都是每位Java开发人员应该熟悉的,并且十分有用的库。Java生态系统非常庞大的,你会发现有很多不同的类库可以做不同的事情。每个你想到的东西,都可能有一个库可以做到。
要相信,你遇到的问题,肯定不止你一个遇到过。
要相信,也许有很多人比你更勤奋。
要相信,你用或不用,轮子就在那里。
要相信,使用这些类库,你和你的代码都会变得更好。
作者:Hollis
- ?
Java注解解析-运行时注解详解(RUNTIME)
霍霸
展开
一 注解的定义
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明 。如果要对于元数据的作用进行分类,还没有明确的定义,不过我们可以根据它所起的作用,注解不会改变编译器的编译方式,也不会改变虚拟机指令执行的顺序,它更可以理解为是一种特殊的注释,本身不会起到任何作用,需要工具方法或者编译器本身读取注解的内容继而控制进行某种操作。大致可分为三类:
编写文档:通过代码里标识的元数据生成文档。
代码分析:通过代码里标识的元数据对代码进行分析。
编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查。
二 用途
因为注解可以再代码编译期间帮我们完成一些复杂的准备工作,所以我们可以利用注解去完成我们的一些准备工作。比如Greendao,我们注解一个实体类,它要处理成好多逻辑关系类,这些逻辑类让我们自己去书写的话那将是一个庞大的代码量, extends AbstractDao等这些类。比如BufferKnife,我们用注解将控件的属性传递给它,它将生成一些功能类去处理这些值,***_ViewBinding等这些类型的类。运行时注解的使用,比如Retrofit的@GET或者@POST等等都是运行时注解,它的注解的处理必须跟Retrofit的对象有关联,所以必须定义成运行时的。所以注解已经成为一种趋势,比如BufferKnife,EventBus,Darrger,Greendao,Arouter,Retrofit。。。看来我们也要去完成我们的一个注解了。
三 知识准备
Java JDK中包含了三个注解分别为@Override(校验格式),@Deprecated:(标记过时的方法或者类),@SuppressWarnnings(注解主要用于抑制编译器警告)等等java1.8之后有新增了一些注解像@FunctionalInterface()这样的,对于每个注解的具体使用细节这里不再论述。我们可以通过点击这里来看一下专业解释! 来看一下@Override的源码。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
}
通过源代码的阅读我们可以看出生命注解的方式为@interface,每个注解都需要不少于一个的元注解的修饰,这里的元注解其实就是修饰注解的注解,可以理解成最小的注解单位吧。。。下面详细的看下每个注释注解的意义吧:
@Target:
说明了Annotation所修饰的对象范围,也就是我们这个注解是用在那个对象上面的:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。以下属性是多选状态,我们可以定义多个注解作用域,比如:
@Target({ElementType.METHOD,ElementType.FIELD}),单个的使用 @Target(ElementType.FIELD)。
(1).CONSTRUCTOR:构造方法声明。
(2).FIELD:用于描述域也就是类属性之类的,字段声明(包括枚举常量)。
(3).LOCAL_VARIABLE:用于描述局部变量。
(4).METHOD:用于描述方法。
(5).PACKAGE:包声明。
(6).PARAMETER:参数声明。
(7).TYPE:类、接口(包括注释类型)或枚举声明 。
(8) .ANNOTATION_TYPE:注释类型声明,只能用于注释注解。
官方解释:指示注释类型所适用的程序元素的种类。如果注释类型声明中不存在 Target 元注释,则声明的类型可以用在任一程序元素上。如果存在这样的元注释,则编译器强制实施指定的使用限制。 例如,此元注释指示该声明类型是其自身,即元注释类型。它只能用在注释类型声明上:
@Target(ElementType.ANNOTATION_TYPE)
public @interface MetaAnnotationType {
}
此元注释指示该声明类型只可作为复杂注释类型声明中的成员类型使用。它不能直接用于注释:
@Target({})
public @interface MemberType {
...
}
这是一个编译时错误,它表明一个 ElementType 常量在 Target 注释中出现了不只一次。例如,以下元注释是非法的:
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD})
public @interface Bogus {
...
}
@Retention:
定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。来源于java.lang.annotation.RetentionPolicy的枚举类型值:
(1).SOURCE:在源文件中有效(即源文件保留)编译成class文件将舍弃该注解。
(2).CLASS:在class文件中有效(即class保留) 编译成dex文件将舍弃该注解。
(3).RUNTIME:在运行时有效(即运行时保留) 运行时可见。
也就是说注解处理器能处理这三类的注解,我们通过反射的话只能处理RUNTIME类型的注解.
官方解释:指示注释类型的注释要保留多久。如果注释类型声明中不存在 Retention 注释,则保留策略默认为 RetentionPolicy.CLASS。只有元注释类型直接用于注释时,Target 元注释才有效。如果元注释类型用作另一种注释类型的成员,则无效。
@Documented:
指示某一类型的注释将通过 javadoc 和类似的默认工具进行文档化。应使用此类型来注释这些类型的声明:其注释会影响由其客户端注释的元素的使用。如果类型声明是用 Documented 来注释的,则其注释将成为注释元素的公共 API 的一部。Documented是一个标记注解,没有成员。
@Inherited:
元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。 注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。
官方解释:指示注释类型被自动继承。如果在注释类型声明中存在 Inherited 元注释,并且用户在某一类声明中查询该注释类型,同时该类声明中没有此类型的注释,则将在该类的超类中自动查询该注释类型。此过程会重复进行,直到找到此类型的注释或到达了该类层次结构的顶层 (Object) 为止。如果没有超类具有该类型的注释,则查询将指示当前类没有这样的注释。
注意,如果使用注释类型注释类以外的任何事物,此元注释类型都是无效的。还要注意,此元注释仅促成从超类继承注释;对已实现接口的注释无效。
@Repeatable:
Repeatable可重复性,Java 1.8新特性,其实就是把标注的注解放到该元注解所属的注解容器里面。可重复性的意思还是用demo来解释一下吧:
//定义了一个 注解里面属性的返回值是其他注解的数组
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCar {
MyTag[] value(); ----MyTag 这里就是MyTag注解的容器。
}
//另外一个注解 就是上一个注解返回的注解
@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
@Repeatable(MyCar.class) --------这里添加这个属性之后 我们的这个注解就可以重复的添加到我们定义的容器中了,注意里面的值时 我们定义的容器注解的class对象.
public @interface MyTag { ........MyTag
String name () default "" ;
int size () default 0 ;
}
//使用
@MyTag(name = "BWM", size = 100)
@MyTag()
public Car car;
//如果我们的注解没有@Repeatable的话,这样写的话是报错的,加上之后就是这样的了
这个注解是很特殊的,我们的注解中有@Repeatable(MyCar.class)这样的元注解的话,就是说当前标注的注解(MyTag注解)放到我们的值(MyCar.class)这个注解容器里面。那么我们再处理注解的时候获取到的是我们最后的注解容器(MyCar注解),这样说有点生硬下面看demo:
使用:
public class HomeActivity extends AppCompatActivity {
@MyTag(name = "BWM", size = 100)
@MyTag(name = "大众" ,size = 200) ......这里用了它的重复性.
Car car;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
AnnotationProccessor.instance().inject(this); //这里去处理注解
// Log.e("WANG", "HomeActivity.onCreate." + car.toString());
}
}
处理过程:
Class aClass = o.getClass();
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field:declaredFields) {
if(field.getName().equals("car")){
Annotation[] annotations = field.getAnnotations();
for (int i = 0; i
Annotation annotation = annotations[i];
//我们获取的该字段上面的注解只有一个 那就是 MyCar注解,看结果1的打印.
//但是我们明明标注的是 MyTag. 为什么获取的是注解容器呢.
//这就是@Repeatable的强大之处.
Class aClass1 = annotation.annotationType();
Log.e("WANG","AnnotationProccessor.MyCar"+aClass1 );
}
MyCar annotation = field.getAnnotation(MyCar.class);
MyTag[] value = annotation.value();
for (int i = 0; i
MyTag myTag = value[i];
Log.e("WANG","AnnotationProccessor.MyTag name value is "+myTag.name() );
}
}
结果是:
AnnotationProccessor.MyCarinterface cn.example.wang.routerdemo.annotation.MyCar.1
AnnotationProccessor.MyTag name value is BWM.2
AnnotationProccessor.MyTag name value is 大众.3
三 自定义运行时注解
通过以上的学习我们知道@interface是声明注解的关键字,每个注解需要注明生命周期以及作用范围.你可以给注解定义值.也就是再注解内部定义我们需要的方法.这样注解就可以再自己的生命周期内为我们做事.这里我们就自定义一个为一个对象属性初始化的注解吧,类似于Dagger的功能。
public @interface MyTag {
}
注解里面的定义也是有规定的:
注解方法不能带有参数。注解方法返回值类型限定为:基本类型、String、Enums、Annotation或者这些类型的数组。注解方法可以有默认值。注解本身能够包含元注解,元注解被用来注解其他注解。
我们就来试一下吧!
public @interface MyTag {
//声明返回值类型,这里可没有大括号啊,可以设置默认返回值,然后就直接";"了啊。
String name () default "" ;
int size () default 0 ;
}
定义好了注解我们就来规定我们自定义的注解要在哪里用?要何时用?因为我们这里使用了反射来处理注解,反射就是在代码的运行的时候通过class对象反相的去获取类内部的东西,不熟悉反射机制的请移步这里Android开发者必须了解的反射基础,所以我们定义该注解的生命周期在运行时,并且该注解的的目的是为自定义属性赋值,那么我们的作用域就是FIELD。这里面定义了我们要初始化的bean的基本属性,给了默认值。这样我们就可以用该注解去创建我们需要的bean对象。
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTag {
String name () default "" ;
int size () default 0 ;
}
好了接下来看怎么使用我们的这个自定义的注解!
public class HomeActivity extends AppCompatActivity {
@MyTag(name = "BMW",size = 100)
Car car;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
//这里我们要首先注册一下这个类
AnnotationCar.instance().inject(this);
//当程序运行的时候这里将会输出该类Car的属性值。
Log.e("WANG","Car is "+car.toString());
}
}
注解如果没有注解处理器,那么该注解将毫无意义。这里呢我们在这个Activity里面定义了一个Car类的属性,然后再car这个变量上面定义我们的注解,并且给我们的注解赋值。然后我们再onCreate方法里面初始化我们的注解处理器。然后运行代码,log日志将打印Car类的信息,先来看下结果吧
cn.example.wang.routerdemo E/WANG: Car is Car [name=BMW, size=100]
这样我们的自定义注解就有作用了,下面是”注解处理器“的代码,这里都是我们自己编写的处理注解的代码,其实系统是自带注解处理器的,不过它一般用来处理源码注释和编译时注释。
//自定义的类
/**
* Created by WANG on 17/11/21.
*/
public class AnnotationCar {
private static AnnotationCar annotationCar;
public static AnnotationCar instance(){
synchronized (AnnotationCar.class){
if(annotationCar == null){
annotationCar = new AnnotationCar();
}
return annotationCar;
}
}
public void inject(Object o){
Class aClass = o.getClass();
Field[] declaredFields = aClass.get...
- ?
PHPexcel读取excel数据
单半山
展开
PHPExcel是一个PHP类库,用来帮助我们简单、高效实现从Excel读取Excel的数据和导出数据到Excel。也是我们日常开发中,经常会遇到的使用场景。PHPExcel可以快速导入客户信息,避免人工录入信息的麻烦。这里分享下读取数据的过程
1. 下载PHPexcel, 我这里下载的PHPExcel-1.8
2. 将下载的文件解压缩拷贝到项目目录中,如图:
3. 准备好要读取的excel文件,如图:
4. 加载PHPexcel文件并读取数据:
5. 读取结果如下:
- ?
VS2017下编写C 程序读写Excel文件
凝雁
展开
前言:
有时候我们需要对Excel文件进行特殊处理,这种情况下写个小程序是很方便的。最近刚开始学C#,正好有同学需要处理个Excel文件,我就写了一个程序。发现网上虽有资料,但很多行不通,特此记录,以免后来人少走弯路。
正文:
首先,界面如下,当然,程序员不需要看界面,从代码中就可以直接学习。
然后,需要下载一个文件“Microsoft.Office.Interop.Excel.dll”,自行网搜。导入到引用之中。然后也把System.Windows.Forms加入引用。
最后,上代码。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
//ghw:add
using System.Windows.Forms;
using Excel = Microsoft.Office.Interop.Excel;
namespace WpfExcel
{
///
/// MainWindow.xaml 的交互逻辑
///
public partial class MainWindow : Window
{
public Excel.Application excel;
public Excel.Workbooks wbs;
public Excel.Workbook wb;
public Excel.Worksheets wss;
public Excel.Worksheet ws;
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
System.Windows.Forms.OpenFileDialog fd = new OpenFileDialog();
fd.Filter = @"Excel文件(*.xls; *.xlsx)|*.xls; *.xlsx|All File(*.*)|*.*";
if(fd.ShowDialog()==System.Windows.Forms.DialogResult.OK)
{
filePath.Text = fd.FileName;
}
}
private void BtnAna_Click(object sender, RoutedEventArgs e)
{
try
{
excel= new Excel.Application();
wbs = excel.Workbooks;
wb = wbs.Add(filePath.Text);
int ncount = wb.Worksheets.Count;
if (ncount < 1)
{
System.Windows.Forms.MessageBox.Show("没有内容");
return;
}
else
{
// System.Windows.Forms.MessageBox.Show("ok,继续");
}
for(int i=0; i
{
ws = (Excel.Worksheet)wb.Sheets.Item[i+1];
cbSheet.Items.Add(ws.Name);
}
cbSheet.Text = ws.Name;
for(int i=0;i<10;i++)
{
cbLeft.Items.Add(i+1);
cbLeftNum.Items.Add(i + 1);
cbRight.Items.Add(i + 1);
cbRightNum.Items.Add(i + 1);
}
cbLeft.Text = "2";
cbLeftNum.Text = "3";
cbRight.Text = "4";
cbRightNum.Text = "5";
// excel.Quit();
// excel = null;
}
catch(Exception ex)
{
System.Windows.Forms.MessageBox.Show("解析数据异常,请检查数据结构");
}
finally
{
excel.Quit();
excel = null;
}
}
private void BtnRes_Click(object sender, RoutedEventArgs e)
{
try
{
int nMin = Convert.ToInt32(tbMin.Text);
int nMax = Convert.ToInt32(tbMax.Text);
excel = new Excel.Application();
wbs = excel.Workbooks;
wb = wbs.Add(filePath.Text);
int ncount = wb.Worksheets.Count;
if (ncount < 1)
{
System.Windows.Forms.MessageBox.Show("没有内容");
return;
}
else
{
// System.Windows.Forms.MessageBox.Show("ok,继续");
}
ws = wb.Sheets[cbSheet.Text];
if(ws.Columns.Count<1)
{
System.Windows.Forms.MessageBox.Show("没有内容");
}
else
{
// System.Windows.Forms.MessageBox.Show("ok,继续");
}
string s1="01234";
int MaxIndex = 222;
string[,] lrData = new string[MaxIndex, 4];
int leftArr = Convert.ToInt32(cbLeft.Text);
int leftNumArr = Convert.ToInt32(cbLeftNum.Text);
int rightArr = Convert.ToInt32(cbRight.Text);
int rightNumArr = Convert.ToInt32(cbRightNum.Text);
int leftNum = 0;
for(int i=1;i< (MaxIndex+1);i++)
{
if(((Excel.Range)ws.Cells[i, leftArr]).Text =="")
{
break;
}
else
{
lrData[leftNum, 0]= ((Excel.Range)ws.Cells[leftNum+1, leftArr]).Text;
lrData[leftNum, 1] = ((Excel.Range)ws.Cells[leftNum + 1, leftNumArr]).Text;
leftNum++;
}
}
int rightNum = 0;
for (int i = 1; i < (MaxIndex + 1); i++)
{
if (((Excel.Range)ws.Cells[i, rightArr]).Text == "")
{
break;
}
else
{
lrData[rightNum, 2] = ((Excel.Range)ws.Cells[rightNum + 1, rightArr]).Text;
lrData[rightNum, 3] = ((Excel.Range)ws.Cells[rightNum + 1, rightNumArr]).Text;
rightNum++;
}
}
Excel.Worksheet ws1 = (Excel.Worksheet)wb.Worksheets.Add(Type.Missing, Type.Missing, Type.Missing, Type.Missing);
ws1.Name = "result";
int nl = 0;
int nr = 0;
for(int x=0;x
{
for(int y=0;y
{
ws1.Cells[x * rightNum + y + 1, 1] = lrData[x, 0];
ws1.Cells[x * rightNum + y + 1, 2] = lrData[x, 1];
ws1.Cells[x * rightNum + y + 1, 3] = lrData[y, 2];
ws1.Cells[x * rightNum + y + 1, 4] = lrData[y, 3];
ws1.Cells[x * rightNum + y + 1, 5] = lrData[x, 0] + lrData[y, 2];
ws1.Cells[x * rightNum + y + 1, 6] = lrData[x, 1] + "+" + lrData[y, 3];
nl = Convert.ToInt32(lrData[x, 1]);
nr = Convert.ToInt32(lrData[y, 3]);
ws1.Cells[x * rightNum + y + 1, 7] = Convert.ToString(nl + nr);
}
}
wb.SaveAs(cbSheet.Text+".xlsx");
wb.Save();
wb.Close();
System.Windows.Forms.MessageBox.Show("结果文件保存在 我的文档 中,命名为:"+ cbSheet.Text + ".xlsx");
}
catch(Exception ex)
{
System.Windows.Forms.MessageBox.Show("解析数据异常,请检查数据结构");
}
finally
{
excel.Quit();
excel = null;
}
}
}
}
写完之后,我觉得Excel公式可能很方便的就能实现这个程序的功能,我虽为程序员,但是真的对那些公式有点陌生,虽说学起来可能很快,但就是没学,竟然有种“隔行如隔山”的感觉。
不敢说自己没有时间,前段时间晚上回家,看完了《铁齿铜牙纪晓岚》四部曲,最近也看完了《宰相刘罗锅》,惭愧。
中间插:每日可行,长按copy本行 道4亚汇宁斯忆34挨非 打开阿里家的支F宝领钱。
我觉得应该没有人能看到这。如果有桌面无聊的人请留言哦!
C#现在真是尴尬,java在手机端(Android)和web端(服务器)上很有市场,C#想进入桌面应用,但是有老大哥MFC(C++),现在QT又风生水起,win7和WinXP份额还很大, 你认为,C-Sharp的前景怎么样呢?
真希望微软的真能跨平台啊,可惜微软短期内不会帮助竞争对手了。
助人者会助己吗?
要么C#死、Windows活,要么Windows死、C#活?
肯定不是。
平台不跨平台,C#顶多奄奄一息而已。
跨平台,Windows可能活的更好。
————分割线————
耿然原创,勤了周更,懒了月更。
欢迎评论、吐槽、爆料、投诉、建议。
评论比文章更精彩。
————分割线————
- ?
集算器协助java处理多样性数据源之Excel
Jesse
展开
Java程序员读取和计算excel的程序一般要使用poi或其它开源包,这些开源包对编程的支持较为底层,整体学习成本和操作复杂度都很高。使用集算器辅助java处理excel文件就可以避免这些事务。
下面通过一个例子看一下具体作法:从Excel文件orders.xls中读取订单信息,找出2010年1月1日(含)之后,SELLERID等于18的订单。orders.xls的内容如下:
实现的思路是:用Java程序调用集算器脚本,读取和计算excel文件中的数据,之后将结果以ResultSet的方式返回给Java程序。由于集算器支持动态表达式解析和求值,使得Java程序可以像使用sql那样,灵活的处理数据。
首先,程序员可以将条件“2010年1月1日(含)之后,并且SELLERID等于18的订单。”作为参数where传递给esProc程序,如下图:
where是个字串,其值为:ORDERDATE>=date(2010,1,1) && SELLERID==18。
esProc的程序代码如下:
A2:按照条件过滤。这里使用宏来实现动态解析表达式,其中的where就是传入参数。集算器将先计算${…}里的表达式,将计算结果作为宏字符串值替换${…}之后解释执行。这个例子中最终执行的是:=A1.select(ORDERDATE>=date(2010,1,1) && SELLERID==18)。A1:定义一个file对象,导入excel数据。esProc的集成开发环境可以直观的显示出导入的数据,如上图右边部分。importxls函数也可以读写xlsx文件,它会根据文件扩展名自动判断excel的版本。
A3:将符合条件的结果集返回给java。如果需要将结果写入另外一个excel文件,只要将A3单元格改为:=file("D:/file/orders_result.xls").exportxls@t(A2)。
过滤条件发生变化时不用改变程序,只需改变where参数即可。例如,条件变为:2010年1月1日(含)之后,并且SELLERID等于18的订单,或者CLIENT等于PWQ的订单。Where的参数值可以写为:CLIENT=="PWQ"||ORDERDATE>=date(2010,1,1) && SELLERID==18。执行之后,A2中的结果集如下图:
在Java程序中使用esProc JDBC调用这段程序获得结果的代码如下:(将上述esProc程序保存为test.dfx):
//建立esProc jdbc连接
Class.forName("com.esproc.jdbc.InternalDriver");
con= DriverManager.getConnection("jdbc:esproc:local://");
//调用esProc程序(存储过程),其中test是dfx的文件名
com.esproc.jdbc.InternalCStatementst =(com.esproc.jdbc.InternalCStatement)con.prepareCall("call test(?)");
//设置参数
st.setObject(1,"ORDERDATE>=date(2010,1,1) && SELLERID==18 || CLIENT==\"PWQ\"");//执行esProc存储过程
ResultSet set =st.executeQuery();
对于代码较简单的脚本,还可以把代码直接写在调用集算器JDBC的Java程序中,而不必专门编写脚本文件(test.dfx):
ResultSet set = st.executeQuery(
"=file(\"D:/file/orders.xls\").importxls@t().select(ORDERDATE>=date(2010,1,1) && SELLERID==18 || CLIENT==\"PWQ\")");
这段Java代码直接调用了集算器的一句脚本:从Excel文件中取得数据,并按照指定的条件过滤。
- ?
一行代码完成Java的Excel读写
黑魂
展开
前段时间在 github 上发现了阿里的 EasyExcel 项目,觉得挺不错的,就写了一个简单的方法封装,做到只用一个函数就完成 Excel 的导入或者导。刚好前段时间更新修复了一些 BUG,就把我的这个封装分享出来,请多多指教。
附上源码:
https://github/HowieYuan/easyexcel-method-encapsulation
EasyExcel
EasyExcel 的 github 地址:
https://github/alibaba/easyexcel
EasyExcel 的官方介绍:
可以看到 EasyExcel 最大的特点就是使用内存少,当然现在它的功能还比较简单,能够面对的复杂场景比较少,不过基本的读写完全可以满足。
一. 依赖
首先是添加该项目的依赖,目前的版本是 1.0.2。
com.alibaba easyexcel 1.0.2 二. 需要的类
1. ExcelUtil
工具类,可以直接调用该工具类的方法完成 Excel 的读或者写。
2. ExcelListener
监听类,可以根据需要与自己的情况,自定义处理获取到的数据,我这里只是简单地把数据添加到一个 List 里面。
publicclassExcelListenerextendsAnalysisEventListener {//自定义用于暂时存储data。//可以通过实例获取该值private List
3. ExcelWriterFactroy
用于导出多个 sheet 的 Excel,通过多次调用 write 方法写入多个 sheet。
4. ExcelException
捕获相关 Exception。
三. 读取 Excel
读取 Excel 时只需要调用 ExcelUtil.readExcel() 方法:
@RequestMapping(value = "readExcel", method = RequestMethod.POST)public Object readExcel(MultipartFile excel) {return ExcelUtil.readExcel(excel, new ImportInfo());}
其中 excel 是 MultipartFile 类型的文件对象,而 new ImportInfo() 是该 Excel 所映射的实体对象,需要继承 BaseRowModel 类,如:
publicclass ImportInfo extends BaseRowModel {@ExcelProperty(index = 0)privateString name;@ExcelProperty(index = 1)privateString age;@ExcelProperty(index = 2)privateString email;publicString getName() {return name; }publicvoid setName(String name) {this.name = name; }publicString getAge() {return age; }publicvoid setAge(String age) {this.age = age; }publicString getEmail() {return email; }publicvoid setEmail(String email) {this.email = email; }}
作为映射实体类,通过 @ExcelProperty 注解与 index 变量可以标注成员变量所映射的列,同时不可缺少 setter 方法。
四. 导出 Excel
1. 导出的 Excel 只拥有一个 sheet
只需要调用 ExcelUtil.writeExcelWithSheets() 方法:
@RequestMapping(value = "writeExcel", method = RequestMethod.GET)publicvoidwriteExcel(HttpServletResponse response) throws IOException { List
list = getList(); String fileName = "一个 Excel 文件"; String sheetName = "第一个 sheet"; ExcelUtil.writeExcel(response, list, fileName, sheetName, new ExportInfo()); } fileName,sheetName 分别是导出文件的文件名和 sheet 名,new ExportInfo() 为导出数据的映射实体对象,list 为导出数据。
对于映射实体类,可以根据需要通过 @ExcelProperty 注解自定义表头,当然同样需要继承 BaseRowModel 类,如:
publicclass ExportInfo extends BaseRowModel {@ExcelProperty(value = "姓名" ,index = 0)privateString name;@ExcelProperty(value = "年龄",index = 1)privateString age;@ExcelProperty(value = "邮箱",index = 2)privateString email;@ExcelProperty(value = "地址",index = 3)privateString address;}
value 为列名,index 为列的序号。
如果需要复杂一点,可以实现如下图的效果:
对应的实体类写法如下:
publicclass MultiLineHeadExcelModel extends BaseRowModel {@ExcelProperty(value = {"表头1","表头1","表头31"},index = 0)privateString p1;@ExcelProperty(value = {"表头1","表头1","表头32"},index = 1)privateString p2;@ExcelProperty(value = {"表头3","表头3","表头3"},index = 2)private int p3;@ExcelProperty(value = {"表头4","表头4","表头4"},index = 3)private long p4;@ExcelProperty(value = {"表头5","表头51","表头52"},index = 4)privateString p5;@ExcelProperty(value = {"表头6","表头61","表头611"},index = 5)privateString p6;@ExcelProperty(value = {"表头6","表头61","表头612"},index = 6)privateString p7;@ExcelProperty(value = {"表头6","表头62","表头621"},index = 7)privateString p8;@ExcelProperty(value = {"表头6","表头62","表头622"},index = 8)privateString p9;}
2. 导出的 Excel 拥有多个 sheet
调用 ExcelUtil.writeExcelWithSheets() 处理第一个 sheet,之后调用 write() 方法依次处理之后的 sheet,最后使用 finish() 方法结束。
publicvoidwriteExcelWithSheets(HttpServletResponse response) throws IOException { List
list = getList(); String fileName = "一个 Excel 文件"; String sheetName1 = "第一个 sheet"; String sheetName2 = "第二个 sheet"; String sheetName3 = "第三个 sheet"; ExcelUtil.writeExcelWithSheets(response, list, fileName, sheetName1, new ExportInfo()) .write(list, sheetName2, new ExportInfo()) .write(list, sheetName3, new ExportInfo()) .finish();} write 方法的参数为当前 sheet 的 list 数据,当前 sheet 名以及对应的映射类。
扩展阅读
代码整洁之道|最佳实践小结
Javascript 将 HTML 页面生成 PDF 并下载
Java POI 导出EXCEL经典实现 Java导出Excel弹出下载框
来源:https://juejin.im/post/5ba320546fb9a05d0b14304b
文章来源网络,版权归作者本人所有,如侵犯到原作者权益,请与我们联系删除
- ?
整理关于java读取excel内容的例子供大家参考
沙鸥
展开
1POI简介
Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。
2POI下载
poi下载地址:https://apache.org/dyn/closer.lua/poi/release/bin/poi-bin-3.17-20170915.tar.gz
下载之后把压缩包解压,然后在项目里面引用解压文件夹里面的jar
3新建java project,引入poi相关的jar
4创建一个java类,编写代码
package test;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
public class ReadExcel {
/**
* @param args
*/
@SuppressWarnings("resource")
public static void main(String[] args) {
try {
InputStream is = new FileInputStream(new File(
"D:/360bizhi/0_TITLE_CODE.xls"));
HSSFWorkbook hssfWorkbook = new HSSFWorkbook(is);
// 获取每一个工作薄
for (int numSheet = 0; numSheet < hssfWorkbook.getNumberOfSheets(); numSheet++) {
HSSFSheet hssfSheet = hssfWorkbook.getSheetAt(numSheet);
if (hssfSheet == null) {
continue;
}
// 获取当前工作薄的每一行
for (int rowNum = 0; rowNum <= hssfSheet.getLastRowNum(); rowNum++) {
HSSFRow hssfRow = hssfSheet.getRow(rowNum);
if (hssfRow != null) {
String title_id = String.valueOf(hssfRow.getCell(0));
// 读取第一列数据
String title_name = String.valueOf(hssfRow.getCell(1));
// 读取第二列数据
String title_name_en = String.valueOf(hssfRow
.getCell(2));
System.out.println("===============title_id:"
+ title_id + ",title_name:" + title_name
+ ",title_name_en:" + title_name_en);
} catch (Exception e) {
e.printStackTrace();
5运行main进行测试,查看打印结果
打印结果和xls里面的值是一样的,说明读取excel成功
请大家多多关注我的头条号,谢谢大家
java读取excel
-
1、只需3秒快速实现求和
-
2、如何快速填充序号
-
3、如何自动填充序号(公式法)
-
4、数据条的神奇应用
-
5、多文本快速合并
-
6、查找与替换的不同玩法
-
7、快速定位到指定区域
-
8、数据排序、工资条制作
-
9、快速筛选(模糊、精确筛选)
-
10、快速插入空行
-
11、快速删除空行
-
12.快速跳转到天涯海角
-
13、.同时查看两个Excel文件
-
14、用条件格式扮靓报表
-
15、一键插入Excel图表
-
16、批量处理行高、列宽
-
17、利用拆分功能查看数据
-
18、批量录入相同内容
-
19、工作表快速跳转
-
20、批量录入表格模板(精品课程)
-
21、Excel函数与公式的应用、公式循环引用的查找
-
22、IF函数单条件判断同比增长
-
23、用sum函数 格式相同,连续多表数据汇总
-
24、excel快捷键
-
25、VLOOKUP函数——根据销售员匹配销售额
-
26、统计各部门销售总额
-
27、统计指定条件个数
-
28、怎样输入当前日期和时间、星期数
-
29、销售业绩排名
-
30、Sumproduct函数-万能函数(销售额汇总求和)
-
31、根据销售员,地区,商品名称汇总
-
32、批量替换PPT字体
-
33、给销售额数据批量添加万元单位
-
34、一秒快速核对两列数据
-
35、快速定位到指定单元格或区域
-
36、快速制作双行标题工资条
-
37、给你的表格做个瘦身
-
38、快速打开常用的Excel文件
-
39、快速打开多个Excel文件
-
40、利用创建组—快速隐藏/展开多列数据
-
41、快速制作下拉菜单
-
42、复制粘贴表格,如何保留数据源列宽格式一致?
-
43、两列数据位置互换
-
44、1秒钟扮靓报表——如何实现表格隔行换色
-
45、快速删除重复记录——保留唯一值
-
46、快速向下填充、向右填充,文本或公式
-
47、给Excel文件添加密码
-
48、插入带图片的批注
-
49、输入公式后不计算?
-
50、如何设置单元格缩进
-
51、快速解决Excel表格总显示货币格式
-
52、批量添加万元单位
-
53、你会四舍五入么?
-
54、用RAND函数机选彩票
-
55、冻结首行你会么?
-
56、超链接的高级应用
-
57、IFERROR函数-屏蔽错误值
-
58、批量填充颜色
-
59、录入数据
-
60、快速输入工号
-
61、快速行列转置
-
62、自定义缩放界面
-
63、多个单元格同时输入
-
64、如何计算立方米?
-
65、快速制作双行标题工资条
-
66、输入带方框的√和×
-
67、快速将姓名对齐
-
68、快速输入性别
-
69、按单位职务排序
-
70、自动计算合同到期日期
-
71、计算时间间隔
-
72、日期和时间的拆分
-
73、快速处理不规范的日期格式
-
74、快速填充合并单元格
-
75、效率加倍的快捷键
-
76、快速复制表格和对象
-
77、快速创建工作表副本
-
78、快速复制序列号
-
79、快速显示公式
-
80、多个单元格同时输入
-
81、快速调整显示比例
-
82、快速自动填充
-
83、快速填充(Ctrl+E)
-
84、Ctrl与数字键结合
-
85、快速将多列数据整理为1列
-
86、快速将1列数据拆分为多列
-
87、快速定位公式
-
88、快速录入数据
-
89、快速累计求和
-
90、身份证号码显示为0怎么办?
-
91、快速制作斜线表头
-
92、文本竖向显示
-
93、神奇的监视窗口
-
94、不一样的格式刷
-
95、快速美化图表
-
96、快速生成当前日期
-
97、快速找出循环引用
-
98、快速提取信息
-
99、二维表快速转换为一维表
-
100、快速多表合并